简介

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

形式

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

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

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

def target():
print('running target()') target = decorate(target)

两种写法的最终结果一样:上述两个代码片段执行完毕后得到的target 不一定是原来那个 target 函数,而是 decorate(target) 返回的函数。

严格来说,装饰器只是语法糖。如前所示,装饰器可以像常规的可调用对象那样调用,其参数是另一个函数。有时,这样做更方便,尤其是做元编程(在运行时改变程序的行为)时。
综上,装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二个特性是,装饰器在加载模块时立即执行。

执行装饰器

装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。这通常是在导入时(即 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 响应的函数上的注册处。这种注册装饰器可能会也可能不会修改被装饰的函数。

最新文章

  1. pointers on c (day 1,chapter3)
  2. jQuery的ajax中return语句无法返回值
  3. android 图片浏览器
  4. 【原创】CDM添加新磁盘,然后负载
  5. [转] 判断html页是否滚动停止
  6. RouterOS的MikroTik脚本从DNS更新IPSEC端的IP地址
  7. UVA 11090 Going in Cycle!!(二分答案+判负环)
  8. Servlet课程0426(九)Servlet服务器端创建Cookie和客户端读取Cookie
  9. springMVC学习笔记--初识springMVC
  10. 【技术贴】解决 myeclipse打不开报错an error has occurred, see .
  11. SQL Server 完美SPLIT函数
  12. js获取光标位置
  13. qrcode生成二维码插件
  14. 关于微信小程序,一些想法
  15. typedef 使用
  16. 第26月第29天 ffmpeg yasm
  17. 批量插入数据, 将DataTable里的数据批量写入数据库的方法
  18. C#用WebBrowser与WIN API辅助模拟获取网站完整Cookie
  19. Unity3D学习笔记(十三):委托、考试复习
  20. mysql中要根据某个逗号分割的字符串关联查询另一张表的数据

热门文章

  1. Source Insight 中的 Auto Indenting
  2. TensorFlow从0到1之TensorFlow逻辑回归处理MNIST数据集(17)
  3. jmeter录制app测试脚本
  4. 11.实战交付一套dubbo微服务到k8s集群(3)之dubbo微服务底包镜像制作
  5. linux最小化安装命令补全
  6. Redis快照原理详解
  7. 傻瓜式教学--win10 + frp + rdpwrap + 阿里云服务器 --实现win10 多用户同时远程登录内网机
  8. drf-Authentication认证
  9. NPM 配置文件修改
  10. 深入浅出腾讯BERT推理模型--TurboTransformers