装饰器相关知识
装饰器是一个可以调用的对象,接收的参数是一个函数,装饰器可以改变被装饰的函数,然后返回原函数或者其他可以调用的对象
将函数替换成另外的函数
1 | def deco(func): |
特性
- 能把被装饰的函数替换成其他函数。
- 装饰器在加载模块时立即执行
例如在导入一个py文件时,文件中包含有装饰器以及被装饰的函数,那么导入后,会发现实际上装饰器已经执行了封装的效果,引入的函数是已经装饰过的
变量作用域
- 一般来说,函数体中的变量优先在函数体内寻找,如果找不到那么才从全局作用域寻找,
- 但要注意
+=
的使用,使用该运算符的前提是变量已经定义。 - 并且,如果在打印输出的后有定义该变量,那么执行依然会报错
1 | y = 7 |
global可以使用该参数,定义全局变量
闭包
对一个函数进行了延伸,可以使用被装饰函数外的非全局变量
1 | // 计算动态平均值 |
- series是make_averager函数的局部变量,返回后该局域变量域就已经结束了
- 对averager函数而言,series是一个自由变量(指未在本地作用域中绑定的变量)
- 闭包是一种函数,它会保留定义函数时存在的自由变量的绑定, 这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定
- 只有嵌套在其他函数中的函数才可能需要处理不在全局作用域中的外部变量
注意
- 自由变量必须是一个可变的对象,否则在被装饰函数体内使用该变量会报错未定义
1 | def make_averager(): |
- python3中有关键字
nonlocal
,可以保存在闭包中使用的变量
functools模块中常用装饰器
functools.wraps
该装饰器可以将被装饰的函数属性复制到装饰函数中,常用来恢复被装饰函数修改过的name和doc属性
1 | import time |
functools.lu_cache
主要用来缓存,它把耗时的函数的结果保存起来,避免传入相同的参数时重复计算。LRU 三个字母是“Least Recently Used”的缩写,表明缓存不会无限制增长,一段时间不用的缓存 条目会被扔掉。
functools.singleddispatch
将一个装饰器扩展成多个来使用,可以在系统的任何地方和 任何模块中注册专门函数。如果后来在新的模块中定义了新的类型,可 以轻松地添加一个新的专门函数来处理那个类型。此外,你还可以为不 是自己编写的或者不能修改的类添加自定义函数
1 | from functools import singledispatch |
参数化装饰器
创建一个装饰器 工厂函数,把参数传给它,返回一个装饰器,然后再把它应用到要装饰 的函数上。
1 | registry = set() |