说到Python装饰器,我相信您想到的就是这样的代码:
@decorator
def some_func():
.....
或者
@decorator(params=True)
def some_func():
.....
如果你的经验丰富,你可能看到过这样的:
@module.decorator(params=True)
def some_func():
.....
但是像下面这样的,你见过吗?
@buttons[0].clicked.connect
def spam():
...
你肯定没见过,因为这种语法是非法的。不过....很快它就要合法了。
其实本质上装饰器也是一个函数,没什么特殊的。所以理论上只要一个表达式最终结果是一个有装饰器功能的函数,写在@后面就应该是可以的。但是Python之前对装饰器的语法还是有比较严格的限制的,这么做的理由是,Guido觉得在找到第一个“放开限制会使代码可读性更好”的例子之前,保持克制更加稳妥。不过,现在这个例子出现了,就是GUI按钮的事件响应。PyQt的开发者们觉得下面的代码可读性更好:
buttons = [QPushButton(f'Button {i}') for i in range(10)]
@buttons[0].clicked.connect
def spam():
...
@buttons[1].clicked.connect
def eggs():
...
这段代码由于装饰器语法的限制,现在不得不这样写:
button_0 = buttons[0]
@button_0.clicked.connect
def spam():
...
button_1 = buttons[1]
@button_1.clicked.connect
def eggs():
...
即便现在这样不放开限制,实际上开发者们想出了好几种hack的方式绕过装饰器的语法限制,比如:
def _(x):
return x
@_(buttons[0].clicked.connect)
def spam():
...
@eval("buttons[1].clicked.connect")
def eggs():
...
既然不限制更加可读,同时也限制不住,不如索性放开吧!这个放开的想法获得了Guido的支持,现在进入了讨论阶段。说不定年末的Python3.9就会放开装饰器的语法限制了吧~
放开到什么程度呢?基本上就是能放在 if 、for 后面作为表达式的语句都可以接受(也有少量例外)。
非常期待?你也可以看看这个PEP的原文,了解更详细的细节:https://www.python.org/dev/peps/pep-0614/