Decoradores en Python: Una introducción para principiantes

Aprende cómo los decoradores pueden mejorar las capacidades y eficiencia de tus funciones en Python.

Python es un lenguaje de programación de alto nivel que ha ganado inmensa popularidad en los últimos años. Es un lenguaje versátil con una amplia gama de características que lo hacen la opción más cómoda para escribir código limpio, eficiente y potente.

Una de las características clave que hace que Python sea un gran lenguaje para trabajar es su soporte para los decoradores. En este artículo haremos una introducción a esta potente característica de Python, cuyo dominio nos permitirá seguir aprovechando al máximo las capacidades de este lenguaje en las tareas que realizamos a diario.

¿Qué es un Decorador?

En Python, un decorador es un tipo especial de función que puede modificar el comportamiento de otra función sin cambiar su código fuente. Los decoradores se pueden utilizar para agregar nuevas funcionalidades a funciones existentes, modificar la salida de una función o proporcionar comportamiento adicional cuando se llama a una función.

Para utilizar un decorador, se define como una función Python regular y luego se aplica a otra función usando el símbolo @. Veamos un ejemplo sencillo:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

En este ejemplo, definimos una función decoradora llamada my_decorator que toma una función como argumento y devuelve una nueva función llamada wrapper. Dentro de wrapper, imprimimos un mensaje antes y después de llamar a la función original.

Luego, aplicamos la función my_decorator a la función say_hello usando el símbolo @. Cuando llamamos a say_hello, se llama a la función wrapper creada por la función my_decorator.

La salida de este código sería:

Before the function is called.
Hello!
After the function is called.

Como se puede ver, la función wrapper está modificando el comportamiento de la función say_hello agregando una salida adicional antes y después de que se llame a say_hello.

Otra forma de aplicar un decorador es haciendo un llamado a la función decoradora y pasar la función original como argumento:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

def say_hello():
    print("Hello!")

decorated_function = my_decorator(say_hello)
decorated_function()

En este caso, creamos una función decoradora llamada my_decorator y una función regular llamada say_hello. Luego, llamamos a la función my_decorator y pasamos say_hello como argumento, lo que devuelve una nueva función llamada wrapper. Luego, asignamos esta nueva función a una variable llamada decorated_function y la llamamos.

La salida de este código sería la misma que en el ejemplo anterior:

Before the function is called.
Hello!
After the function is called.

Los decoradores también pueden recibir argumentos. Veamos un ejemplo:

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper():
            for i in range(num_times):
                func()
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def say_hello():
    print("Hello!")

say_hello()

En este ejemplo, definimos una función decoradora llamada repeat que recibe un argumento num_times. Esta función devuelve otra función decoradora llamada decorator_repeat, que a su vez devuelve la función wrapper que llama a la función original varias veces.

Luego, aplicamos el decorador repeat a la función say_hello, pasando num_times=3. Cuando llamamos a say_hello, se llama a la función wrapper creada por la función decorator_repeat, que llama a say_hello tres veces.

La salida de este código sería:

Hello!
Hello!
Hello!

Como se puede ver, la función wrapper está modificando el comportamiento de la función say_hello al llamarla varias veces, como se especifica en el argumento num_times pasado al decorador repeat.

Los decoradores también se pueden utilizar para modificar la salida de una función. Veamos un ejemplo de esto:

def uppercase(func):
    def wrapper():
        original_result = func()
        modified_result = original_result.upper()
        return modified_result
    return wrapper

@uppercase
def say_hello():
    return "Hello!"

print(say_hello())

En este ejemplo, definimos una función decoradora llamada uppercase que toma una función como argumento y devuelve una nueva función llamada wrapper. Dentro de wrapper, llamamos a la función original y almacenamos su salida en una variable llamada original_result. Luego, modificamos esta salida convirtiéndola en mayúsculas y devolvemos el resultado modificado.

Luego, aplicamos el decorador uppercase a la función say_hello. Cuando llamamos a say_hello, llama a la función wrapper creada por la función uppercase.

La salida de este código sería:

HELLO!

Como se puede ver, la función wrapper está modificando la salida de la función say_hello convirtiéndola en mayúsculas.

Conclusiones

En conclusión, los decoradores son una característica poderosa de Python que permite modificar el comportamiento de las funciones sin cambiar su código fuente. Los decoradores se pueden utilizar para agregar nueva funcionalidad a funciones existentes, modificar la salida de una función o proporcionar un comportamiento adicional cuando se llama a una función.

Los decoradores también pueden recibir argumentos, lo que le permite personalizar su comportamiento para diferentes casos de uso. Comprender los decoradores es una parte importante para convertirse en un programador de Python competente.

En este post vimos ejemplos de funciones decoradoras, que modifican el comportamiento de otras funciones. Sin embargo, Python también nos permite decorar clases y utilizar clases como decoradores. Este es un tema en el que estaremos profundizando en futuros artículos en nuestro blog, así que mantente al tanto y suscríbete al newsletter para que no te pierdas ningún contenido nuevo!

Esperamos que este post te haya sido útil y recuerda que también te puede interesar:

¡Muchas gracias por leernos!

Did you find this article valuable?

Support Blog CodeXL by becoming a sponsor. Any amount is appreciated!