社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python 炫技操作: 创造"新语法"的黑科技

Python编程时光 • 3 年前 • 432 次点击  

我们今天来看一段炫技代码。它可以把任何能接收两个参数的函数定义成一个特殊的运算符。

例如,我们知道Python里面的range函数,最少可以接收1个参数,最多能够接收3个参数。当只有两个参数的时候,格式为range(开始, 结束),从开始数字到结束数字逐次加1,左闭右开。使用今天的方法,可以把它的写法改为开始 |到| 结束,如下图所示:

又比如,urllib.parse.urljoin可以把域名和一个相对路径拼接起来: urljoin(域名, 相对路径),我们也可以改写成如下图所示的格式:

这种炫技有余,实用不足的功能是怎么实现的呢?其实原理非常简单,只有8行代码:

from functools import partial

class Change(object):
    def __init__(self, func):
        self.func = func
    def __or__(self, other):
        return self.func(other)
    def __ror__(self, other):
        self.func = partial(self.func, other)
        return self

这里就涉及到一个盲点和两个真正的知识点。这个盲点就是,你可能以为 |到|是一个字符,但是它是3个字符;你可能会把|拼接|看做一个整体,但是它实际上是3个部分:左边的|拼接和右边的|

我们把空格加上,就很明显了:

两个真正的知识点,就是__or____ror__这两个魔术方法和偏函数partial。而Change本身就是一个普通的类而已,__or____ror__定义了这个类的实例在左侧遇到|时,右侧遇到|时的具体行为。

我们一个一个来讲。首先是__or__。它定义了实例的右侧遇到|时的具体行为。例如,我们用一个简单的代码来进行测试:

class Test:
    def __init__(self, num):
        self.num = num
    def __or__(self, other) :
        print(f'我右边有一个东西,它是:{other}')

x = Test(100)
x | 55

运行效果如下图所示:

但如果你把竖线放在左边,他就会报错,如下图所示:

__ror__就是用来定义|在实例左边的时候,它的行为:

所以,我们最开始的例子中,2 |到| 10,实际上应该理解为:

  1. Change(range)返回的实例
  2. 2 | 到 生成一个中间对象,我们假设它是x
  3. x | 10 生成结果

在我们演示的例子中,2 | 到首先进入了Change类的__ror__方法中:

    def __ror__(self, other):
        self.func = partial(self.func, other)
        return self

其中,一开始的self.func就是我们在初始化实例Change(range)时传入的参数range。所以partial(self.func, other)等价于partial(range, 2)。关于偏函数partial,大家可以看我这篇文章:偏函数:在Python中设定默认参数的另一种办法。简单来说,使用偏函数,可以给一个真正的函数传一部分参数,过一会再补剩下的参数。

可能大家在日常的开发者,很少会让一个实例方法返回self。关于这个写法,大家可以看我的这一篇文章:一日一技:在Python里面实现链式调用。也就是说,1 | 到返回的,依然是Change类的一个实例,我们简称它为x。这个实例的属性self.func的值是partial(range, 2)

接下来,x | 10,调用的是__or__ 方法,于是,此时执行的是partial(range, 2)(10)。偏函数的参数补全了,于是它里面的range真正运行了起来,成为了range(2, 10)

至此,这个Change类我们就解析透了。大家知道,在Python里面,魔术方法是有很多的,如果你不想用|,你还可以用其它的,例如:

或者:

或者:

同时,这个Change类,你甚至可以直接当做装饰器来使用。任何能够接收两个参数的函数,都能使用这个装饰器。例如:

最后总结一下。大家都知道,我是非常反对在工作代码中炫技的,因为炫技的写法很难读,很难维护。今天这个炫技的方法,虽然我也不推荐大家用在工作中,但是它短短8行代码里面,包含了很多个知识点,这就值得大家玩一玩了。






Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/126767
 
432 次点击