浅析函数装饰器和闭包(一)

函数装饰器用于在源码中”标记”函数,以某种方式增强函数的行为。这是一项强大的功能,但是若想掌握,必须理解闭包。

  • 装饰器基础知识

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。

假如有个名为decorate的装饰器:

@decorate
def target():
    print("running target()")

上述代码的效果与下述写法一样:

def target():
    print("running target()")

target = decorate(target)

两种写法的最终结果一样:上述两个代码片段执行完毕后得到的target不一定是原来那个target函数,而是decorate(target)返回的函数。
这里写图片描述
严格来说,装饰器只是语法糖。装饰器可以像常规的可调用对象那样调用,其参数是另一个函数。

综上,装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二个特性是,装饰器在加载模块时立刻执行。

  • Python何时执行装饰器

装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。这通常是在导入时(即Python加载模块时)

例如registration.py模块所示

# registry保存被@register装饰的函数引用
registry = []

def register(func):
    print('running register(%s)' % func)
    registry.append(func)
    return func


@register
def f1():
    print('running f1()')


@register
def f2():
    print('running f2()')


def f3():
    print('running f3()')


def main():
    print('running main()')
    print('registry ->', registry)
    f1()
    f2()
    f3()


if __name__ == '__main__':
    main()
$ python registration.py
running register(<function f1 at 0x7f27b31fb620>)
running register(<function f2 at 0x7f27b31fbbf8>)
running main()
registry -> [<function f1 at 0x7f27b31fb620>, <function f2 at 0x7f27b31fbbf8>]
running f1()
running f2()
running f3()

注意,register在模块中其他函数之前运行(两次)。加载模块后,registry中有两个被装饰函数的引用: f1和f2。这两个函数,以及f3,只有在main明确调用它们时才执行

如果导入registration.py模块(不作为脚本运行),输出如下:

>>> import registration
running register(<function f1 at 0x7f89fb45df28>)
running register(<function f2 at 0x7f89fb46b048>)

此时查看registry的值,得到的输出如下:

扫描二维码关注公众号,回复: 3087791 查看本文章
>>> registration.registry
[<function f1 at 0x7f89fb45df28>, <function f2 at 0x7f89fb46b048>]

综上,函数装饰器在导入模块时立即执行,而被装饰的函数只有在明确调用时运行。另外,装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。还有就是,实际上,大多数装饰器会在内部定义一个函数,然后将其返回。

猜你喜欢

转载自blog.csdn.net/Jonms/article/details/80888604
今日推荐