漂亮的Python装饰器

Cas*_*ash 3 python decorator

我怎么能很好地写一个装饰师?

特别的问题包括:与其他装饰者的兼容性,保留签名等.

如果可能的话,我想避免依赖于装饰器模块,但如果有足够的优势,那么我会考虑它.

有关

  • 保留装饰功能的签名 - 更具体的问题.这里的答案是使用第三方装饰器模块用@ decorator.decorator注释装饰器

Cas*_*ash 6

使用functools来保留名称和文档.签名不会被保留.

直接来自doc.

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print 'Calling decorated function'
...         return f(*args, **kwds)
...     return wrapper
...
>>> @my_decorator
... def example():
...     """Docstring"""
...     print 'Called example function'
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'
Run Code Online (Sandbox Code Playgroud)


Chr*_* B. 5

写一个好的装饰者与写一个好的功能没什么两样.理想情况下,这意味着使用docstrings并确保装饰器包含在您的测试框架中.

你绝对应该使用decorator库或更好functools.wraps()的标准库中的装饰器(从2.5开始).

除此之外,最好让你的装饰师保持狭隘的聚焦和精心设计.不要使用*args或者**kw如果你的装饰者需要特定的参数.而填写你所期望的参数,所以不是:

def keep_none(func):
    def _exec(*args, **kw):
        return None if args[0] is None else func(*args, **kw)

    return _exec
Run Code Online (Sandbox Code Playgroud)

... 使用 ...

def keep_none(func):
    """Wraps a function which expects a value as the first argument, and
    ensures the function won't get called with *None*.  If it is, this 
    will return *None*.

    >>> def f(x):
    ...     return x + 5
    >>> f(1)
    6
    >>> f(None) is None
    Traceback (most recent call last):
        ...
    TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
    >>> f = keep_none(f)
    >>> f(1)
    6
    >>> f(None) is None
    True"""

    @wraps(func)
    def _exec(value, *args, **kw):
        return None if value is None else func(value, *args, **kw)

    return _exec
Run Code Online (Sandbox Code Playgroud)