Python 装饰器是 Python 中常常使用到的一种语法糖, 它可以大幅度减少重复代码, 使用起来十分方便另一方面, 装饰器的定义往往会导致出现函数重重嵌套的情况, 这会给装饰器的实现者带来阅读代码的困难
本文剖析 Python 装饰器的定义与用法
不带参数的装饰器
我们先来看一下不带参数的装饰器的实现, 这种情况比较简单以下是一个不带参数的装饰器的使用例子:
- @decorator
- def fun():
- print('fun() is called')
前面提到, 装饰器只是 Python 提供的语法糖, 使用 @decorator 作为装饰器相当于:
- def fun():
- print('fun() is called')
- fun = decorator(fun)
我们再来看一下装饰器 decorator 本身的定义装饰器可以使用函数实现, 也可以使用类来实现, 这里我们介绍函数的实现方式
- def decorator(fun):
- def decorated_function():
- print('before fun, do something')
- fun()
- print('after fun, do something')
- return decorated_function
装饰器 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
带参数的装饰器
装饰器支持带参数, 我们先来看下带参数的装饰器的使用方式
- @cached(5)
- def fun():
- print('fun() is called')
上面带参数的装饰器的使用, 等价于以下的代码:
- def fun():
- print('fun() is called')
- fun = cached(5)(fun)
装饰器 cached 被定义成一个函数, 它的定义如下:
- def cached(timeout):
- def decorator(func):
- def decorated_function():
- print('before fun, do something, timeout=%d' % timeout)
- func()
- print('after fun, do something, timeout=%d' % timeout)
- return decorated_function
- return decorator
即 cached 是一个函数, 它接受一个 timeout 的形参, 并返回一个 decorator 的函数 cached(5) 会进行函数调用且函数的实参为 5, 并返回 decoratordecorator 也是个函数, 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/
来源: http://blog.csdn.net/lihao21/article/details/79338962