装饰器的一个关键性特性是,他们在被装饰的函数定义之后立即执行。这通常是在导入时(即python加载模块时)
registry = [ ] #1
def register(func):#2
print('running register(%s)'%func)#3
registry.append(func)#4
return func #5
@register #6
def f1():
print('running f1()')
@register
def f2():
print('running f2()')
def f3():#7
print('running f3()')
def main():#8
print('running main()')
print('registry ->',registry)
f1()
f2()
f3()
if__name__ == "__main__":
main()#9
#1 registry 保存被@register装饰的函数引用
#2 register 的参数是一个函数
#3 为了演示,显示被装饰的函数
#4 把 func 存入registry
#5 返回func: 必须返回函数;这里返回的函数与通过参数传入的一样
#6 f1 和 f2 被@registry。
#7 f3没有装饰
#8 main显示registry,然后调用f1(),f2(),f3().
#9 只有把registration.py 当作脚本运行时调用main()。
把registration.py当作脚本运行得到输出如下:
$ python3 registration.py
running register(<function f1 at 0x100631bf8>)
running register(<function f2 at 0x100632c80>)
running main()
registry -> [<function f1 at 0x100631bf8>,<function f2 at 0x100631c80>]
running f1()
running f2()
running f3()
注意,register在模块中其他函数之前运行(两次)。调用register时,传给它的参数是被装饰的函数,例如<function f1 at 0x100631bf8>.
加载模块后,registry中被装饰函数的引用:f1和f2.这两个函数,以及f3,只在main明确调用他们时才执行。
如果导入registration.py模块(不作为脚本运行),输出如下:
import registration
running register(<function f1 at 0x10063b1e0>)
running register(<function f2 at 0x10063b268>)
此时查看registry的值,得到的输出如下:
registration.registry
[<function f1 at 0x10063b1e0>,<function f2 at 0x10063b268>]
装饰器函数与被装饰的函数在同一个模型中定义。实际情况是,装饰器通常在一个模型中定义,然后应用到其他模块中的函数上。
register装饰器返回的函数与通过参数传入的相同。实际上,大多数装饰器会在内部定义一个函数,然后将其返回。