返回介绍

7.2 Python 何时执行装饰器

发布于 2024-02-05 21:59:47 字数 2276 浏览 0 评论 0 收藏 0

装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。这通常是在导入时(即 Python 加载模块时),如示例 7-2 中的 registration.py 模块所示。

示例 7-2 registration.py 模块

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()  ➒

❶ registry 保存被 @register 装饰的函数引用。

❷ register 的参数是一个函数。

❸ 为了演示,显示被装饰的函数。

❹ 把 func 存入 registry。

❺ 返回 func:必须返回函数;这里返回的函数与通过参数传入的一样。

❻ f1 和 f2 被 @register 装饰。

❼ f3 没有装饰。

❽ main 显示 registry,然后调用 f1()、f2() 和 f3()。

❾ 只有把 registration.py 当作脚本运行时才调用 main()。

把 registration.py 当作脚本运行得到的输出如下:

$ python3 registration.py
running register(<function f1 at 0x100631bf8>)
running register(<function f2 at 0x100631c80>)
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>]

示例 7-2 主要想强调,函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。这突出了 Python 程序员所说的导入时运行时之间的区别。

考虑到装饰器在真实代码中的常用方式,示例 7-2 有两个不寻常的地方。

装饰器函数与被装饰的函数在同一个模块中定义。实际情况是,装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。

register 装饰器返回的函数与通过参数传入的相同。实际上,大多数装饰器会在内部定义一个函数,然后将其返回。

虽然示例 7-2 中的 register 装饰器原封不动地返回被装饰的函数,但是这种技术并非没有用处。很多 Python Web 框架使用这样的装饰器把函数添加到某种中央注册处,例如把 URL 模式映射到生成 HTTP 响应的函数上的注册处。这种注册装饰器可能会也可能不会修改被装饰的函数。下一节会举例说明。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文