Los decoradores en Python son una característica poderosa y flexible del lenguaje que permiten modificar el comportamiento de una función o clase de forma transparente. Básicamente, un decorador es una función que toma otra función como argumento y devuelve una nueva función que extiende o modifica el comportamiento de la función original.
Decoradores en Python
Los métodos estáticos
Los métodos estáticos en Python son aquellos que no están ligados a una instancia de una clase, sino a la clase en sí. Esto significa que los métodos estáticos no pueden acceder a los atributos de una instancia de una clase y no reciben una referencia a una instancia de la clase como argumento.
Los métodos estáticos se definen utilizando el decorador @staticmethod
y se pueden invocar a través de la clase en sí, sin tener que crear una instancia de la clase. Por ejemplo:
class Math:
@staticmethod
def add(a, b):
return a + b
result = Math.add(1, 2)
print(result) # Output: 3
En este ejemplo, el método add
es un método estático que se puede invocar a través de la clase Math
, sin tener que crear una instancia de la clase. Los métodos estáticos son útiles cuando no se requiere acceder a los atributos de una instancia de una clase y se desea proporcionar una función que se pueda invocar directamente a través de la clase.
Un apunte sobre decoradores
Un decorador en Python es una función que toma como entrada una función o una clase y devuelve una nueva función o clase con algún tipo de comportamiento adicional. Los decoradores se utilizan para aplicar funcionalidades adicionales a una función o clase sin tener que modificar su código fuente.
Los decoradores se definen utilizando el símbolo @ seguido del nombre del decorador. Por ejemplo:
def mi_decorador(func):
def envolvente():
print("Antes de nuestra función")
func()
print("Después de nuestra función")
return envolvente
@mi_decorador
def hola():
print("Hola!")
hola()
En este ejemplo, la función mi_decorador
es un decorador que toma como entrada una función y devuelve una nueva función envolvente
que contiene el comportamiento adicional. La función hola
se ha decorado con el decorador mi_decorador
utilizando el símbolo @. Cuando se invoca la función hola
, el decorador se ejecuta primero, agregando el comportamiento adicional antes y después de la invocación de la función original.
Mas sobre los decoradores
Los decoradores se definen usando la sintaxis «@decorador» justo antes de la definición de una función. Esto indica que la función será pasada como argumento al decorador y que la función resultante será asignada a la variable que originalmente contenía la función.
Los decoradores se utilizan comúnmente para añadir funcionalidades como registro, validación de entradas, control de acceso, caché, entre otras. Por ejemplo, se puede definir un decorador que registre cada llamada a una función, o un decorador que agregue una capa de seguridad para limitar el acceso a ciertas funciones.
También es posible combinar múltiples decoradores en una sola función, lo que permite crear cadenas de decoradores que proporcionan múltiples capas de funcionalidad. Cabe destacar que los decoradores son una característica avanzada de Python y pueden ser complejos de entender al principio, pero una vez que se comprende su funcionamiento pueden resultar muy útiles para escribir código modular y reutilizable.
¿como puedo utilizar en el decorador los parámetros de la función que decora?
Para utilizar los parámetros de la función que se está decorando dentro del decorador, se pueden utilizar los argumentos de la función interna del decorador y definirlos como argumentos de la función original. De esta manera, los valores pasados a la función original se pueden utilizar en el decorador.
Aquí te dejo un ejemplo de cómo se puede definir un decorador que utiliza los parámetros de la función que se está decorando:
def mi_decorador(funcion):
def funcion_modificada(*args, **kwargs):
print("Se está ejecutando la función con los siguientes argumentos:")
for arg in args:
print(arg)
for key, value in kwargs.items():
print(key, ":", value)
resultado = funcion(*args, **kwargs)
print("La función ha terminado de ejecutarse.")
return resultado
return funcion_modificada
@mi_decorador
def mi_funcion(a, b, c=3):
print("Esta es mi función original con argumentos a =", a, ", b =", b, ", c =", c)
return a + b + c
resultado = mi_funcion(1, 2, c=4)
print("El resultado de la función es:", resultado)
En este ejemplo, el decorador mi_decorador
recibe como argumento la función funcion. La función interna del decorador, funcion_modificada
, utiliza el operador *args
y **kwargs
para capturar todos los argumentos posicionales y de palabras clave que se pasan a la función original.
Dentro de funcion_modificada
, se utiliza un bucle for
para imprimir los valores de los argumentos de la función original. Luego, se llama a la función original con los mismos argumentos que se pasaron a funcion_modificada
, y se almacena el resultado en una variable resultado.
Finalmente, el decorador imprime un mensaje después de la ejecución de la función original y devuelve el resultado.
En la definición de mi_funcion
, no se especifica ningún decorador. En cambio, se llama a la función con los argumentos 1
, 2
y c=4
. El decorador mi_decorador
se aplica automáticamente a la función mi_funcion
porque está definido como el decorador justo encima de la definición de mi_funcion
.
Al ejecutar este código, la salida sería:
Se está ejecutando la función con los siguientes argumentos:
1
2
c : 4
Esta es mi función original con argumentos a = 1 , b = 2 , c = 4
La función ha terminado de ejecutarse.
El resultado de la función es: 7
Como puedes ver, el decorador ha capturado los argumentos de la función original y ha agregado la funcionalidad adicional de imprimir los valores de los argumentos antes de ejecutar la función original.
¿Puedo alterar los parámetros que le paso a una función desde su decorador?
Es posible alterar los parámetros que se le pasan a una función desde su decorador. Para hacer esto, puedes modificar los valores de los parámetros antes de pasarlos a la función original.
Aquí te dejo un ejemplo de cómo se puede modificar un parámetro en un decorador:
def mi_decorador(funcion):
def funcion_modificada(a, b):
a = a + 1
b = b * 2
resultado = funcion(a, b)
return resultado
return funcion_modificada
@mi_decorador
def mi_funcion(a, b):
resultado = a + b
return resultado
resultado = mi_funcion(2, 3)
print(resultado)
En este ejemplo, el decorador mi_decorador
recibe como argumento la función funcion
. La función interna del decorador, funcion_modificada
, recibe los mismos parámetros que la función original, a
y b
, pero los modifica antes de llamar a la función original. En este caso, a
se incrementa en 1
y b
se duplica.
Dentro de funcion_modificada
, se llama a la función original con los nuevos valores de a
y b
, y se almacena el resultado en una variable resultado.
En la definición de mi_funcion
, no se especifica ningún decorador. En cambio, se llama a la función con los argumentos 2
y 3
. El decorador mi_decorador
se aplica automáticamente a la función mi_funcion
porque está definido como el decorador justo encima de la definición de mi_funcion
.
Al ejecutar este código, la salida sería:
11
Como puedes ver, el valor de a
se incrementó en 1
y el valor de b
se duplicó antes de llamar a la función original. El resultado de la función es 11
, que es el resultado de sumar a
y b
después de aplicar las modificaciones del decorador.
¿Como le puedo pasar valores a la función desde el decorador?
Para pasar valores a la función desde el decorador, se puede utilizar el concepto de argumentos posicionales y de palabras clave en Python. La idea básica es que el decorador reciba los argumentos necesarios y los pase a la función original cuando se llame a ésta.
Aquí te dejo un ejemplo de cómo se puede definir un decorador que toma un argumento y lo pasa a la función:
def mi_decorador(argumento):
def decorador_interno(funcion):
def funcion_modificada():
print("Se está ejecutando la función con argumento:", argumento)
funcion(argumento)
print("La función ha terminado de ejecutarse.")
return funcion_modificada
return decorador_interno
@mi_decorador(argumento="Hola, mundo")
def mi_funcion(argumento):
print("Esta es mi función original con argumento:", argumento)
mi_funcion()
En este ejemplo, el decorador mi_decorador
recibe el argumento argumento y devuelve un nuevo decorador decorador_interno
. Este último decorador toma la función original funcion
como argumento y devuelve una nueva función funcion_modificada
, que incluye el argumento argumento y llama a la función original con ese argumento.
En la definición de mi_funcion
, se utiliza el decorador .@mi_decorador. con el argumento argumento="Hola, mundo"
. Esto significa que la función mi_funcion
será pasada como argumento al decorador mi_decorador
con el valor de argumento igual a "Hola, mundo"
, y la función resultante (funcion_modificada
) será asignada a la variable mi_funcion
.
Finalmente, al llamar a mi_funcion
, se ejecuta la nueva función funcion_modificada
, que incluye el argumento "Hola, mundo"
y llama a la función original con ese argumento.
Al ejecutar este código, la salida sería:
Se está ejecutando la función con argumento: Hola, mundo
Esta es mi función original con argumento: Hola, mundo
La función ha terminado de ejecutarse.
Como puedes ver, el decorador ha pasado el argumento "Hola, mundo"
a la función original y ha agregado la funcionalidad adicional de imprimir un mensaje antes y después de ejecutar la función original.
El vídeo
Lo mismo, pero en Vídeo
Para pasar valores a la función desde el decorador, se puede utilizar el concepto de argumentos posicionales y de palabras clave en Python. La idea básica es que el decorador reciba los argumentos necesarios y los pase a la función original