原文链接: http://www.kylin-ux.com/2017/04/17/language-python-装饰器
装饰器的顺序
1 2 3 4 5
| @a @b @c def f (): pass
|
等效于
1 最初, foo功能为打印’foo’
1 2
| def foo(): print('foo')
|
2 后来由于各种原因, 需要在原功能基础上添加日志输出
1 2 3
| def foo(): print('foo') print('logging.info foo')
|
如果有N个函数都需要添加日志输出…
3 所以添加一个函数, 先打印日志输出, 再调用foo
1 2 3
| def log_func(func): print('logging.info {0}'.format(func.__name__)) func()
|
现在不用修改N个函数了, 但, 原所有调用foo()
的地方, 需要改为log_func(foo)
还是要改很多地方… 对, 我们可以用sed
批量修改
4 现在来个返回函数的函数
1 2 3 4 5 6
| def log_func_d(func): def wrapper(*args, **kwargs): print('logging.info {0}'.format(func.__name__)) return func(*args, **kwargs) return wrapper
|
现在不用修改调用foo()的地方了, 但需要foo = log_func_d(foo)
5 [装饰器]上场
1 2 3 4 5 6
| @log_func_d def foo_d(): print('foo') foo_d() print(foo_d.__name__) # wrapper
|
foo = log_func_d(foo)
还是不够简洁, 换成@log_func_d
, python提供的语法糖
6 带参数的[装饰器]
1 2 3 4 5 6 7 8 9 10 11 12
| def use_func_d_arg(level): def decorator(func): def wrapper(*args, **kwargs): if level == "warn": logging.warn("%s is running" % func.__name__) return func(*args, **kwargs) return wrapper return decorator @use_func_d_arg(level="warn") def foo(name='foo'): print("i am %s" % name)
|
7 类装饰器
1 2 3 4 5 6 7 8 9 10 11
| class Foo(): def __init__(self, func): self._func = func def __call__(self): print ('class decorator runing') self._func() print ('class decorator ending') @Foo def bar(): print ('bar')
|
拥有__call__
方法的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def log_func_d_f(func): from functools import wraps @wraps(func) def wrapper(*args, **kwargs): print('logging.info {0}'.format(func.__name__)) return func(*args, **kwargs) return wrapper @log_func_d_f def foo_d_f(): print('') print(foo_d_f.__name__) # foo_d_f
|
对比5和8, print的结果, 5输出wrapper
, 8输出foo_d_f