2009-09-10 5 views
3

Comment écrire un décorateur?Belles décoratrices en python

en particulier les questions comprennent: la compatibilité avec d'autres décorateurs, en conservant des signatures, etc.

Je voudrais éviter la dépendance du module décorateur si possible, mais il y avait suffisamment d'avantages, alors je considérer.

connexes

Répondre

5

Écrire un bon décorateur n'est pas différent d'écrire une bonne fonction. Ce qui signifie, idéalement, utiliser docstrings et s'assurer que le décorateur est inclus dans votre cadre de test.

Vous devez absolument utiliser la bibliothèque decorator ou, mieux, le décorateur functools.wraps() dans la bibliothèque standard (depuis la version 2.5). Au-delà de cela, il est préférable de garder vos décorateurs étroitement ciblés et bien conçus. N'utilisez pas *args ou **kw si votre décorateur attend des arguments spécifiques. Et faire remplissage dans les arguments que vous attendez, donc au lieu de:

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

    return _exec 

... l'utilisation ...

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

Utilisez functools pour conserver le nom et doc. La signature ne sera pas conservée.

Directement à partir du 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

Son bon ettiquete pour faire des réponses wiki à vos questions. – voyager

+0

qui a du sens – Casebash