关于python decorators
高阶函数
在python里面decorator看起来是个挺高端大气上档次的词, 不过这个东西在函数式语言里面其实很稀松平常, 用一句话概括起来就是高阶函数的语法糖.
什么叫高阶函数(high order procedures)呢? 就是返回值或者参数是函数的函数. 比如我们现在有个函数
:1
hello_world
这个函数的个功能是打印一行字”hello world”. 现在我们想写一个函数, 它的功能是把
这行字打印10遍, 怎么做呢? 简单:1
hello_word
现在我们站的更高一点, 希望写一个更通用的函数, 可以将任意函数执行任意10次, 要怎么办呢?
可以看到,
这个函数比我们一般的函数更”高级”一些, 它接受的参数是一个函数, 把这个函数进行一些加工(执行10次)后, 返回一个新的函数.
这个函数就是高阶函数.1
ten_times
decorator
理解了高阶函数后, 我们就可以看看decorator了. 我们把前一个例子改为:
这样, 新的
和原来的版本完全等价. 所以说, 1
hello_world_10
其实是以下代码的语法糖:1
@ten_times
原函数带参数
假设我们有如下
函数:1
add
这一次, 我们的
函数希望把原函数的_返回值_乘以10, 怎么做呢?1
ten_times
由此可见, 我们在decorator的定义中, 将新函数的输入传递给原函数即可.
decorator带参数
这次我们想把
写的更加general一些, 我们希望它可以接受一个参数1
ten_times
, 可以将任意函数执行的结果乘以任意次. 首先我们用高阶函数的方式:1
times
现在有点复杂了, 对吧?
首先接受一个参数1
times
, 返回一个函数1
time
, 这个1
times_f
函数接受一个函数1
times_f
作为参数, 然后又返回一个新的函数1
func
. 换句话说, 这个函数返回了一个函数, 后者又返回一个函数.
注意到1
new_func
引用了1
new_func
中的局部变量1
times_f
, 这样的函数被称为闭包(closure). 用decorator的语法糖要怎么写呢?1
func
从之前的经验我们可以看到,
这个函数需要返回一个函数, 所以这里我们知道1
ten_times
也是一个函数,它的返回值是一个函数, 由此可知1
times(10)
是一个返回(返回函数的函数)的函数, 也印证了前面的分析.1
times
一点小问题
我们还是回到比较简单的
这个函数:1
ten_times
我们看到,
的1
add
属性变成了1
__name__
! 仔细想想, 这很正常, 因为ten_times返回的函数就是1
new_func
呀! 我们先暴力fix一下:1
new_func
的确, 这个问题解决了. 不过, 还有
等等属性呢? 每次声明decorator的时候都要这么搞一下, 不蛋疼么?
是的, 我们可以把这些fix的代码放到一起:1
__doc__
这样, 就帮我们完成了这些琐碎的小问题.
这个decorator可以将原函数的属性复制到新的wrapper函数, 使得原函数的docstring, name等不会丢失.
万一python升级了, 函数又有新的属性了, 肿么办?幸运的是, python里面有专门的库函数可以解决这个问题:1
fix_props
这个
的原理就和我们上面的1
wraps
类似.1
fix_props
应用
decorator在python里有挺多应用的, 最典型的是
和1
@classmethod
. 例如:1
@property