《流畅的 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() 是装饰器函数。其返回值是经过修饰的函数。

posted @ 2021-02-27 00:44  模糊计算士  阅读(114)  评论(0编辑  收藏  举报