题
如何写出漂亮的装饰器?
具体问题包括:与其他装饰器的兼容性、签名的保留等。
如果可能的话,我想避免对装饰器模块的依赖,但如果有足够的优势,那么我会考虑它。
有关的
- 保留修饰函数的签名 - 更具体的问题。这里的答案是使用第三方装饰器模块,用@decorator.decorator注释装饰器
解决方案
编写一个好的装饰器与编写一个好的函数没有什么不同。这意味着,理想情况下,使用文档字符串并确保装饰器包含在您的测试框架中。
你绝对应该使用 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
...使用 ...
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
其他提示
使用 functools 保留名称和文档。签名不会被保留。
直接从 文档.
>>> 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'
不隶属于 StackOverflow