¿Cuáles son algunos usos comunes de los decoradores de Python? [cerrado]
Si bien me gusta considerarme un codificador de Python razonablemente competente, un aspecto del lenguaje que nunca he podido asimilar son los decoradores.
Sé cuáles son (superficialmente), he leído tutoriales, ejemplos, preguntas sobre Stack Overflow y entiendo la sintaxis, puedo escribir la mía propia, ocasionalmente uso @classmethod y @staticmethod, pero nunca se me ocurre usar un decorador para resolver un problema en mi propio código Python. Nunca me encuentro con un problema en el que pienso: "Hmm... ¡esto parece un trabajo para un decorador!"
Entonces, me pregunto si podrían ofrecer algunos ejemplos de dónde han usado decoradores en sus propios programas y, con suerte, tendré un "¡Ajá!" momento y conseguirlos .
Utilizo decoradores principalmente para fines de sincronización.
def time_dec(func):
def wrapper(*arg):
t = time.clock()
res = func(*arg)
print func.func_name, time.clock()-t
return res
return wrapper
@time_dec
def myFunction(n):
...
Los he usado para sincronización.
import functools
def synchronized(lock):
""" Synchronization decorator """
def wrap(f):
@functools.wraps(f)
def newFunction(*args, **kw):
lock.acquire()
try:
return f(*args, **kw)
finally:
lock.release()
return newFunction
return wrap
Como se señaló en los comentarios, desde Python 2.5 puede usar una with
declaración junto con un objeto threading.Lock
(o multiprocessing.Lock
desde la versión 2.6) para simplificar la implementación del decorador a solo:
import functools
def synchronized(lock):
""" Synchronization decorator """
def wrap(f):
@functools.wraps(f)
def newFunction(*args, **kw):
with lock:
return f(*args, **kw)
return newFunction
return wrap
De todos modos, entonces lo usas así:
import threading
lock = threading.Lock()
@synchronized(lock)
def do_something():
# etc
@synchronzied(lock)
def do_something_else():
# etc
Básicamente simplemente coloca lock.acquire()
/ lock.release()
a cada lado de la llamada a la función.
Utilizo decoradores para los parámetros de verificación de tipos que se pasan a mis métodos de Python a través de algún RMI. Entonces, en lugar de repetir el mismo conteo de parámetros, se generan palabrerías una y otra vez.
Por ejemplo, en lugar de:
def myMethod(ID, name):
if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
raise BlaBlaException() ...
Sólo declaro:
@accepts(uint, utf8string)
def myMethod(ID, name):
...
y accepts()
hace todo el trabajo por mí.
Los decoradores se utilizan para cualquier cosa que desee "envolver" de forma transparente con funcionalidad adicional.
Django los usa para incluir la funcionalidad "requiere inicio de sesión" en funciones de visualización , así como para registrar funciones de filtro .
Puede utilizar decoradores de clases para agregar registros con nombre a las clases .
Cualquier funcionalidad suficientemente genérica que pueda "añadir" al comportamiento de una clase o función existente es un juego limpio para la decoración.
También hay una discusión sobre casos de uso en el grupo de noticias Python-Dev señalado por PEP 318 - Decoradores para funciones y métodos .
Para las pruebas de nariz, puede escribir un decorador que proporcione una función o método de prueba unitaria con varios conjuntos de parámetros:
@parameters(
(2, 4, 6),
(5, 6, 11),
)
def test_add(a, b, expected):
assert a + b == expected