¿Cuáles son los usos de los decoradores de Python?
La ropa interior puede servir para tapar la vergüenza, pero no puede protegernos del viento y del frío en invierno. La gente inteligente inventó los pantalones. Con pantalones el bebé ya no pasará frío. Los decoradores son como los pantalones de los que hablamos aquí, aportando calidez al cuerpo sin afectar la función de la ropa interior.
Volvamos a nuestro tema.
Un decorador es esencialmente una función de Python que permite que otras funciones agreguen funcionalidad adicional sin ningún cambio de código. El valor de retorno del decorador también es un objeto de función. A menudo se utiliza en escenarios con requisitos de segmentación, como inserción de registros, pruebas de rendimiento, procesamiento de transacciones, almacenamiento en caché, verificación de permisos, etc. Decorator es un diseño excelente para resolver este tipo de problemas. Con los decoradores, podemos extraer grandes cantidades del mismo código independientemente de las funciones mismas y continuar reutilizándolas. En resumen, el papel de los decoradores es agregar funcionalidad adicional a los objetos existentes.
Veamos primero un ejemplo simple:
def foo():
Print("Soy foo")
Ahora Hay nuevos requisitos y espero registrar el registro de ejecución de la función, así que agregué el código de registro al código:
def foo():
Imprimir ("Soy foo " )
logging.info("foo se está ejecutando")
Bar() y bar2() tienen requisitos similares. ¿Qué debo hacer? ¿Escribir otro registro en la función de barra? Esto da como resultado una gran cantidad de código idéntico. Para reducir la escritura repetida de código, podemos hacer esto y redefinir una función: procesar el registro exclusivamente y luego ejecutar el código comercial real después de procesar el registro.
Definir usando logging (función):
logging.warn("s is running" func.__name__)
func() define column():
print('I am') use_logging(bar)
No es difícil de entender lógicamente,
Pero en este caso, siempre Para pasar una función como parámetro de la función use_logging. Además, este método destruye la estructura lógica original del código. En el pasado, bar () se ejecutaba al ejecutar la lógica empresarial, pero ahora es necesario cambiarlo a use_logging (bar). Entonces, ¿hay una mejor manera? Por supuesto, la respuesta es decorador.
Decoración sencilla
Definir uso de logging (función):
def packaging (*args, **kwargs):
logging .warn("s is running" func.__name__)
return func(*args, **kwargs)
return wrapperdef bar():
imprimir (' Soy bar ')bar = use _ logging(bar)bar()
La función use_logging es un decorador, que envuelve la función que ejecuta el método comercial real en una función, que se parece a use_logging Decorado esta columna. En este ejemplo, cuando una función entra y sale, se denomina aspecto y este método de programación se denomina programación orientada a aspectos.
El símbolo @ es azúcar sintáctico para decoradores. Úselo al definir funciones para evitar reasignaciones.
Definir el registro de uso (función):
def wrapper(*args, **kwargs):
logging.warn("s is running" func .
__name__)
Función de retorno (*parámetro)
Contenedor de retorno @use_loggingdef foo():
print("Soy foo")@use_loggingdef bar() :
Imprimir ("Soy bar") bar()
Como se muestra en la figura anterior, podemos omitir bar =
Use_logging(bar) . Llame a bar() directamente para obtener el resultado deseado. Si tenemos otras funciones similares, podemos continuar llamando al decorador para decorar la función sin modificar la función repetidamente o agregar nuevos paquetes. De esta forma, mejoramos la reutilización del programa y aumentamos la legibilidad del programa.
Usar decoradores en Python es muy conveniente porque las funciones de Python se pueden pasar como parámetros a otras funciones, asignarse a otras variables, devolver valores y definirse en otra función como objetos comunes.
Decoradores con parámetros
Los decoradores también son más flexibles, como los decoradores con parámetros: en la llamada al decorador anterior, como @use_logging, el único parámetro del decorador son las funciones que realizan negocio. La sintaxis de los decoradores nos permite proporcionar parámetros adicionales al llamar, como @decorator(a). Esto proporciona una mayor flexibilidad al escribir y utilizar decoradores.
Definir registro de uso (nivel):
Definir decorador (función):
def wrapper (*args, **kwargs):
Si nivel == "warn ":
logging.warn("s is running" func.__name__)
Función de retorno (*parámetros)
Envoltorio de retorno
devuelve decorador @ use _ logging(level = " warn ")def foo(name = ' foo '):
print("Soy s " nombre ") foo ()
El use_logging anterior es un decorador que permite parámetros. En realidad, es un paquete de funciones del decorador original y devuelve un decorador. Podemos entenderlo como un cierre con parámetros.
<. p>Cuando el usuario llama a @use_logging(level="warn "), Python puede encontrar esta capa de encapsulación y pasar los parámetros al entorno del decoradorDecoradores de clase
Tomemos. un vistazo a los decoradores de clases En comparación con los decoradores de funciones, los decoradores de clases tienen una gran flexibilidad, alta cohesión y encapsulación cuando usan @form. Cuando se adjuntan a una función, también puede confiar en el método \_\_call\_\ en la clase.
Clase Foo(Objeto):
def __init__(self, func):
self _func = func
def __call__( self):
print("Decorador de clase ejecutándose")
self _func()
Print("Decoración de fin de clase")
@Foo
Columna de definición():
Imprimir("Forma de barra")
bar()
functools. wraps
El uso de decoradores reutiliza en gran medida el código, pero tiene un inconveniente, que es la metainformación de la función original Lost, como la cadena de documentación, el __nombre__ y la lista de parámetros de la función.
Veamos primero el ejemplo:
Decorador
Definición de registro (función):
def with_logging(*args, **kwargs):
Función de impresión. __name__ "llamado
return func(*args, **kwargs)
Usar el registro para devolver
func
@loggeddef f ( x):
"""Hacer algunos cálculos" ""
Devolver x x * x
La realización de esta función equivale a:
Definir f(x):
"""Hacer algunos cálculos" ""
return x x * xf = logged(f)
No Es difícil encontrar que la función f se reemplaza por with_logging. Por supuesto, su cadena de documentación, __name__ se convierte en la información de la función with_logging
Imprimir f.__name__ #Imprimir 'con _logging' Imprimir f.__doc__ #No. print.
Este problema es más grave. Afortunadamente, tenemos functools.wraps en sí mismo como un decorador, que puede copiar la metainformación de la función original en la función decoradora, de modo que la función decoradora tenga la misma. metainformación como la función original /p>
Importar definición de contenedor registrado(func) desde functools:
@wraps(func)
def with_logging(*args, **. kwargs):
Función de impresión.__name__ "llamada
return func(*args, **kwargs)
return with _ logging @ logged def f(x ):
"""Hacer algunos cálculos" " "
return x x * xprint f.__name__? # imprime 'f'print f.__doc__? #print "Haz algunos cálculos"
Decoraciones integradas
@staticmathod, @classmethod, @property
El orden de los decoradores
@a@b@cdef f():
Misma familia
f = a(b(c(f)))