/ / Nice Python Decorators - python, decorador

Bonitos decoradores de pitón - pitón, decorador

¿Cómo escribo bien un decorador?

En particular, los temas incluyen: compatibilidad con otros decoradores, conservación de firmas, etc.

Me gustaría evitar la dependencia del módulo decorador si es posible, pero si hubiera suficientes ventajas, entonces lo consideraría.

Relacionado

Respuestas

5 para la respuesta № 1

Escribir un buen decorador no es diferente a escribir una buena función. Lo que significa, idealmente, usar cadenas de documentación y asegurarse de que el decorador esté incluido en su marco de prueba.

Definitivamente deberías usar el decorator biblioteca o, mejor, la functools.wraps() Decorador en la biblioteca estándar (desde 2.5).

Más allá de eso, es mejor mantener a sus decoradores estrechamente enfocados y bien diseñados. No lo use *args o **kw Si su decorador espera argumentos específicos. Y hacer complete los argumentos que espera, así que en lugar de:

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

return _exec

... utilizar ...

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 para la respuesta № 2

Utilice functools para preservar el nombre y el documento. La firma no se conservará.

Directamente desde el 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"