import decorator

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', )

你可能感兴趣的:(import decorator)