Question

Comment puis-je écrire joliment un décorateur?

Les problèmes particuliers incluent: la compatibilité avec d’autres décorateurs, la préservation des signatures, etc.

Je voudrais éviter si possible de dépendre du module décorateur, mais s'il y avait suffisamment d'avantages, je le prendrais en compte.

Connexes

Était-ce utile?

La solution

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

Vous devez absolument utiliser la bibliothèque decorator ou, mieux, le décorateur functools.wraps () dans la bibliothèque standard (à partir de la version 2.5).

Au-delà de cela, il est préférable de garder vos décorateurs concentrés et bien conçus. N'utilisez pas * args ou ** kw si votre décorateur attend des arguments spécifiques. Et ne remplissez que 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

... utilisez ...

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

Autres conseils

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

Directement de 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'
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top