《流畅的 Python》第 7 章笔记
装饰器的内容,之前在 Java 中也遇到过,当时只是懵懵懂懂,一方面是当时自己的水平有限,另一方面,当初的学习资料的讲解也不是那么好。而这本书中的第 7 章这一章,讲装饰器可以说是讲得相当好。大部分内容都是通俗易懂,只有最后一点地方需要小小琢磨一下。
关于装饰器,有几个名词要注意:
- 装饰器函数,返回被装饰的函数或者经过装饰的函数。如果返回的是被装饰的函数,那么,装饰的效果只会在注册装饰器的时候体现,而如果返回的是经过装饰的函数,那么,装饰的效果会在每一次调用该函数时体现。
- 装饰器工厂函数,返回装饰器。顾名思义,其实就是生产装饰器的函数。
registry = set()
def register(active=True): # ①
def decorate(func): # ②
print('running register(active=%s)->decorate(%s)'%(active, func))
if active:
registry.add(func)
else:
registry.discard(func)
return func
return decorate
@register(active=False)
def f1():
print('running f1()')
@register()
def f2():
print('running f2()')
def f3():
print('running f3()')
if __name__ == '__main__':
f1()
f2()
f3()
f1()
f2()
f3()
# output
"""
running register(active=False)->decorate(<function f1 at 0x000001B4F95DB3A0>)
running register(active=True)->decorate(<function f2 at 0x000001B4F95DB310>)
running f1()
running f2()
running f3()
running f1()
running f2()
running f3()
"""
① register() 是装饰器工厂函数。
② decorate() 是装饰器函数,在这里,其返回的是被装饰的函数本身。
import time
DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args})-> {result}'
def clock(fmt=DEFAULT_FMT): # ①
def decorate(func): # ②
def clocked(*_args):
t0 = time.time()
_result = func(*_args)
elapsed = time.time() - t0
name = func.__name__
args = ', '.join(repr(arg) for arg in _args)
result = repr(_result)
print(fmt.format(**locals())) # 返回当前作用域的变量字典,解包之后,名字对不上的应该直接被函数舍去了
return _result
return clocked
return decorate
if __name__ == '__main__':
@clock()
def snooze(seconds):
time.sleep(seconds)
for i in range(3):
snooze(.123)
# output
"""
[0.12360787s] snooze(0.123)-> None
[0.12413502s] snooze(0.123)-> None
[0.12307119s] snooze(0.123)-> None
"""
① clock() 是装饰器工厂函数。
② decorate() 是装饰器函数。其返回值是经过修饰的函数。