Los decoradores (Decorators) son una parte importante de Python. En pocas palabras: son funciones que modifican la funcionalidad de otras funciones. Ayudan a que nuestro código sea más corto y más "Pythonic" (con estilo Python). La mayoría de los principiantes no saben dónde usarlos, así que voy a compartir en qué áreas los decoradores pueden hacer tu código más limpio. Primero, vamos a discutir cómo escribir tus propios decoradores.
Este es probablemente uno de los conceptos más difíciles de dominar. Lo discutiremos paso a paso, para que puedas entenderlo completamente.
Todo es un objeto
Primero, entendamos las funciones en Python:
Definir funciones dentro de funciones
Eso son los conceptos básicos de las funciones. Llevemos tu conocimiento un paso más allá. En Python podemos definir otra función dentro de una función:
Ahora sabemos que podemos definir otras funciones dentro de una función. Es decir, podemos crear funciones anidadas. Ahora necesitas aprender un poco más: las funciones también pueden devolver funciones.
Devolver funciones desde una función
En realidad, no es necesario ejecutar otra función dentro de una función; también podemos devolverla como salida:
Mira este código otra vez. En la sentencia if/else devolvemos greet y welcome, no greet() y welcome(). ¿Por qué? Porque cuando pones un par de paréntesis después, la función se ejecuta; sin embargo, si no le pones paréntesis, se puede pasar por todas partes y asignarse a otras variables sin ejecutarla. ¿Lo entiendes? Déjame explicarlo con un poco más de detalle.
Cuando escribimosa = hi(),hi()se ejecutará, y como el parámetro name por defecto es yasoob, la funcióngreet()es devuelta.
-
También podemos imprimirhi()(), esto mostrará:now you are in the greet() function。
-
Si cambiamos la sentencia aa = hi(name = "ali"), entonceswelcome()la función será devuelta.
Pasar una función como argumento a otra función
Ahora tienes todo el conocimiento necesario para aprender qué son realmente los decoradores. Los decoradores te permiten ejecutar código antes y después de una función.
Tu primer decorador
En el ejemplo anterior, ¡ya hemos creado un decorador! Ahora modifiquemos el decorador anterior y escribamos un programa un poco más útil:
¿Lo ves? Acabamos de aplicar los principios que aprendimos antes. ¡Esto es exactamente lo que hacen los decoradores en Python! Envuelven una función y modifican su comportamiento de una forma u otra. Ahora quizás te preguntes, en nuestro código no usamos el símbolo@¿símbolo? Eso es solo una forma abreviada de generar una función decorada. Aquí es cómo usamos@para ejecutar el código anterior:
Espero que ahora tengas una comprensión básica de cómo funcionan los decoradores de Python. Si ejecutamos el siguiente código, hay un problema:
print(a_function_requiring_decoration.__name__) # Output: wrapTheFunction
¡Esto no es lo que queríamos! La salida (Output) debería ser "a_function_requiring_decoration". Aquí la función fue reemplazada por warpTheFunction. Sobrescribió el nombre de nuestra función y la cadena de documentación (docstring). Afortunadamente, Python nos proporciona una función simple para resolver este problema: functools.wraps. Modifiquemos el ejemplo anterior para usar functools.wraps:
Ahora es mucho mejor. A continuación, aprendamos algunos casos de uso comunes de los decoradores.
Plantilla estándar:
Nota:@wrapsAcepta una función para decorarla y agrega funcionalidades como copiar el nombre de la función, la cadena de documentación, la lista de parámetros, etc. Esto nos permite acceder a los atributos de la función antes de ser decorada desde dentro del decorador.
Casos de uso
Ahora veamos dónde brillan especialmente los decoradores y cómo usarlos puede hacer que algunas cosas sean más fáciles de manejar.
Autorización (Authorization)
Los decoradores pueden ayudar a verificar si una persona está autorizada para usar un endpoint de una aplicación web. Se usan ampliamente en los frameworks web Flask y Django. Aquí hay un ejemplo de uso de autorización basada en decoradores:
Registro (Logging)
El registro (logging) es otro punto destacado del uso de decoradores. Este es un ejemplo:
Apuesto a que ya estás pensando en otro uso inteligente de los decoradores.
Decoradores con parámetros
Pensemos en esta cuestión: ¿no es @wraps también un decorador? Pero recibe un argumento, como cualquier función normal puede hacer. Entonces, ¿por qué no hacemos lo mismo? Esto es porque cuando usas la sintaxis @my_decorator, estás aplicando una función envolvente que toma una sola función como argumento. Recuerda, en Python todo es un objeto, ¡y esto incluye a las funciones! Con esto en mente, podemos escribir funciones que devuelvan una función envolvente.
Incrustando decoradores en funciones
Volvamos al ejemplo del registro y creemos una función envolvente que nos permita especificar un archivo de registro para la salida.
Clases de decoradores
Ahora tenemos un decorador logit apto para producción, pero cuando ciertas partes de nuestra aplicación todavía son frágiles, las excepciones pueden ser algo que requiera atención más urgente. Por ejemplo, a veces solo quieres registrar en un archivo. Pero a veces quieres enviar un correo electrónico con el problema que llama tu atención, manteniendo también el registro como constancia. Este es un escenario para usar herencia, pero hasta ahora solo hemos visto funciones para construir decoradores.
Afortunadamente, las clases también se pueden usar para construir decoradores. Entonces, ahora reconstruyamos logit usando una clase en lugar de una función.
Esta implementación tiene una ventaja adicional: es más limpia que el enfoque de funciones anidadas, y envuelve una función con la misma sintaxis de antes:
@logit()
def myfunc1():
pass
Ahora, creemos una subclase de logit para añadir la funcionalidad de email (aunque el tema del email no se desarrollará aquí).
A partir de ahora, @email_logit tendrá el mismo efecto que @logit, pero además de registrar, enviará un correo electrónico al administrador.
Dirección original: https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/