2009-09-10 104 views
3

我如何很好地編寫裝飾器?好的Python裝飾器

特別問題包括:與其他裝飾的兼容性,簽名的保護,等等

我想避免的裝飾模塊的依賴如果有可能,但如果有足夠的優勢的話,我會考慮。

相關

回答

5

寫一個好的裝飾器是沒有什麼不同,然後寫一個很好的功能。這意味着,理想情況下,使用docstrings並確保裝飾器包含在您的測試框架中。

您應該在標準庫(自2.5開始)中使用decorator庫或更好的functools.wraps()修飾器。

除此之外,最好讓你的裝飾者集中精力和精心設計。如果您的裝飾器需要特定參數,請勿使用*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 
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' 
+0

其良好ettiquete使維基回答自己的問題。 – voyager 2009-09-11 14:42:43

+0

確實有道理 – Casebash 2009-09-11 23:34:30