Python 装饰器浅析
Python 装饰器是 Python 中常常使用到的一种语法糖,它可以大幅度减少重复代码,使用起来十分方便。另一方面,装饰器的定义往往会导致出现函数重重嵌套的情况,这会给装饰器的实现者带来阅读代码的困难。
本文剖析 Python 装饰器的定义与用法。
不带参数的装饰器
我们先来看一下不带参数的装饰器的实现,这种情况比较简单。以下是一个不带参数的装饰器的使用例子:
1 |
|
前面提到,装饰器只是 Python 提供的语法糖,使用@decorator
作为装饰器相当于:
1 | def fun(): |
我们再来看一下装饰器decorator
本身的定义。装饰器可以使用函数实现,也可以使用类来实现,这里我们介绍函数的实现方式。
1 | def decorator(fun): |
装饰器decorator
被定义成一个函数,这个函数返回一个新的函数。同时,我们看到decorator
接受一个fun
的形参,fun
作为一个函数,会在decorated_function
中被调用。
使用装饰器后,如果调用fun()
,则会输出:
before fun, do something
fun() is called
after fun, do something
通过装饰器decorator
,原来的fun
函数,被赋值成decorator(fun)
,而decorator(fun)
会触发decorator
函数的调用并返回decorated_function
这个函数。在decorated_function
中,会先输出before fun, do something
,然后调用fun()
,最后输出after fun, do something
。
带参数的装饰器
装饰器支持带参数,我们先来看下带参数的装饰器的使用方式。
1 | @cached(5) |
上面带参数的装饰器的使用,等价于以下的代码:
1 | def fun(): |
装饰器cached
被定义成一个函数,它的定义如下:
1 | def cached(timeout): |
即cached
是一个函数,它接受一个timeout
的形参,并返回一个decorator
的函数。cached(5)
会进行函数调用且函数的实参为5,并返回decorator
。decorator
也是个函数,decorator(fun)
(即cached(5)(fun)
)相当于上面不带参数的装饰器的使用,它返回decorated_function
这个函数。
看起来有点复杂,实际上,带参数的装饰器只是在不参数的装饰器的基础上再多一层函数的封装而已,多的这层函数是为了将装饰器的参数传递进去。
使用装饰器后,如果调用fun()
函数,则会输出:
before fun, do something, timeout=5
fun() is called
after fun, do something, timeout=5
参考资料
- http://www.lightxue.com/understand-python-decorator-the-easy-way
- https://mp.weixin.qq.com/s/98JA68TX9X4j6wPABiMJNA
- https://mp.weixin.qq.com/s/Om98PpncG52Ba1ZQ8NIjLA
- http://code.oneapm.com/python/2015/04/27/python-decorator-mistake/
- http://www.jianshu.com/p/d03e4dfc5a78
- http://blog.guoyb.com/2016/04/19/python-decorator/