decorator 是一个帮助你更优雅的编写 decorator 的 decorator
以最常用的 memoize decorator 为例:
原生的写法如下
def memoize(func):
def _memoize(*args, **kw):
if not hasattr(func, 'cache'):
func.cache = {}
if kw: # frozenset is used to ensure hashability
key = args, frozenset(kw.items())
else:
key = args
if key not in func.cache:
func.cache[key] = func(*args, **kw)
return func.cache[key]
return functools.update_wrapper(_memoize, func)
decorator 版如下:
import decorator
@decorator.decorator
def memoize(func, *args, **kw):
if not hasattr(func, 'cache'):
func.cache = {}
if kw: # frozenset is used to ensure hashability
key = args, frozenset(kw.items())
else:
key = args
cache = func.cache # attribute added by memoize
if key not in cache:
cache[key] = func(*args, **kw)
return cache[key]
更复杂的,带参 decorator(or decorator factory)
原生的写法如下
def memoize(print_cache):
def _memoize(func):
def __memoize(*args, **kw):
if not hasattr(func, 'cache'):
func.cache = {}
if kw: # frozenset is used to ensure hashability
key = args, frozenset(kw.items())
else:
key = args
if key not in func.cache:
func.cache[key] = func(*args, **kw)
if print_cache:
print(func.cache)
return func.cache[key]
return functools.update_wrapper(__memoize, func)
return _memoize
decorator 版如下:
@decorator.decorator
def memoize(func, print_cache=False, *args, **kw):
if not hasattr(func, 'cache'):
func.cache = {}
if kw: # frozenset is used to ensure hashability
key = args, frozenset(kw.items())
else:
key = args
cache = func.cache # attribute added by memoize
if key not in cache:
cache[key] = func(*args, **kw)
if print_cache:
print(func.cache)
return cache[key]
总的来说,decorator 允许你只用一个单层的函数定义来编写一个 decorator,而不是像原生的写法那个样需要写成嵌套的形式,让你的精力集中在 decorator 的内容上而不是形式上
此外,即使使用了functools.update_wrapper
,被装饰的函数只会保留__name__, __doc__, __module__, __dict__
,但是会丢失原始函数的 __code__
等,decorator 帮你解决了这个问题
比如
>>> @memoize
>>> def fun(x):
>>> return x
原生写法
>>> print(fun.__code__.co_varnames)
>>> ('args', 'kw', 'key')
decorator 版写法
>>> print(fun.__code__.co_varnames)
>>> ('x', )