Decoradores son una herramienta muy poderosa y útil en Python ya que permite a los programadores modificar el comportamiento de una función o clase. Los decoradores nos permiten envolver otra función para extender el comportamiento de la función envuelta, sin modificarla permanentemente. Pero antes de profundizar en los decoradores, comprendamos algunos conceptos que nos serán útiles para aprender sobre los decoradores.
Objetos de primera clase
En Python, las funciones son objetos de primera clase lo que significa que las funciones en Python se pueden usar o pasar como argumentos.
Propiedades de las funciones de primera clase:
- Una función es una instancia del tipo Objeto.
- Puede almacenar la función en una variable.
- Puede pasar la función como parámetro a otra función.
- Puede devolver la función desde una función.
- Puedes almacenarlos en estructuras de datos como tablas hash, listas,…
Considere los siguientes ejemplos para una mejor comprensión.
Ejemplo 1: Tratar las funciones como objetos.
Python3
# Python program to illustrate functions> # can be treated as objects> def> shout(text):> >return> text.upper()> print>(shout(>'Hello'>))> yell>=> shout> print>(yell(>'Hello'>))> |
>
>
Producción:
HELLO HELLO>
En el ejemplo anterior, hemos asignado la función gritar a una variable. Esto no llamará a la función, sino que toma el objeto de función al que hace referencia un grito y crea un segundo nombre que apunta a él, grito.
Ejemplo 2: Pasar la función como argumento.
Python3
# Python program to illustrate functions> # can be passed as arguments to other functions> def> shout(text):> >return> text.upper()> def> whisper(text):> >return> text.lower()> def> greet(func):> ># storing the function in a variable> >greeting>=> func(>'''Hi, I am created by a function passed as an argument.'''>)> >print> (greeting)> greet(shout)> greet(whisper)> |
>
>
Producción:
HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am created by a function passed as an argument.>
En el ejemplo anterior, la función de saludo toma otra función como parámetro (gritar y susurrar en este caso). La función pasada como argumento luego se llama dentro de la función saludar.
Ejemplo 3: Devolver funciones de otra función.
Python3
polimorfismo java
# Python program to illustrate functions> # Functions can return another function> def> create_adder(x):> >def> adder(y):> >return> x>+>y> >return> adder> add_15>=> create_adder(>15>)> print>(add_15(>10>))> |
>
>
Producción:
25>
En el ejemplo anterior, creamos una función dentro de otra función y luego devolvimos la función creada dentro.
Los tres ejemplos anteriores describen los conceptos importantes que se necesitan para comprender a los decoradores. Después de revisarlos, profundicemos en los decoradores.
Decoradores
Como se indicó anteriormente, los decoradores se utilizan para modificar el comportamiento de una función o clase. En los decoradores, las funciones se toman como argumento en otra función y luego se llaman dentro de la función contenedora.
Sintaxis para decorador:
@gfg_decorator def hello_decorator(): print('Gfg') '''Above code is equivalent to - def hello_decorator(): print('Gfg') hello_decorator = gfg_decorator(hello_decorator)'''> En el código anterior, gfg_decorator es una función invocable, que agregará algo de código encima de otra función invocable, la función hello_decorator y devolverá la función contenedora.
El decorador puede modificar el comportamiento :
Python3
# defining a decorator> def> hello_decorator(func):> ># inner1 is a Wrapper function in> ># which the argument is called> > ># inner function can access the outer local> ># functions like in this case 'func'> >def> inner1():> >print>(>'Hello, this is before function execution'>)> ># calling the actual function now> ># inside the wrapper function.> >func()> >print>(>'This is after function execution'>)> > >return> inner1> # defining a function, to be called inside wrapper> def> function_to_be_used():> >print>(>'This is inside the function !!'>)> # passing 'function_to_be_used' inside the> # decorator to control its behaviour> function_to_be_used>=> hello_decorator(function_to_be_used)> # calling the function> function_to_be_used()> |
>
>
Producción:
Hello, this is before function execution This is inside the function !! This is after function execution>
Veamos el comportamiento del código anterior y cómo se ejecuta paso a paso cuando se llama a function_to_be_used.

Pasemos a otro ejemplo donde podemos descubrirlo fácilmente. el tiempo de ejecución de una función usando un decorador.
Python3
# importing libraries> import> time> import> math> # decorator to calculate duration> # taken by any function.> def> calculate_time(func):> > ># added arguments inside the inner1,> ># if function takes any arguments,> ># can be added like this.> >def> inner1(>*>args,>*>*>kwargs):> ># storing time before function execution> >begin>=> time.time()> > >func(>*>args,>*>*>kwargs)> ># storing time after function execution> >end>=> time.time()> >print>(>'Total time taken in : '>, func.__name__, end>-> begin)> >return> inner1> # this can be added to any function present,> # in this case to calculate a factorial> @calculate_time> def> factorial(num):> ># sleep 2 seconds because it takes very less time> ># so that you can see the actual difference> >time.sleep(>2>)> >print>(math.factorial(num))> # calling the function.> factorial(>10>)> |
>
>
Producción:
3628800 Total time taken in : factorial 2.0061802864074707>
¿Qué pasa si una función devuelve algo o se pasa un argumento a la función?
En todos los ejemplos anteriores, las funciones no devolvieron nada, por lo que no hubo ningún problema, pero es posible que necesites el valor devuelto.
Python3
def> hello_decorator(func):> >def> inner1(>*>args,>*>*>kwargs):> > >print>(>'before Execution'>)> > ># getting the returned value> >returned_value>=> func(>*>args,>*>*>kwargs)> >print>(>'after Execution'>)> > ># returning the value to the original frame> >return> returned_value> > >return> inner1> # adding decorator to the function> @hello_decorator> def> sum_two_numbers(a, b):> >print>(>'Inside the function'>)> >return> a>+> b> a, b>=> 1>,>2> # getting the value through return of the function> print>(>'Sum ='>, sum_two_numbers(a, b))> |
>
>
Producción:
before Execution Inside the function after Execution Sum = 3>
En el ejemplo anterior, puede notar una gran diferencia en los parámetros de la función interna. La función interna toma el argumento como *args y **kwargs, lo que significa que se puede pasar una tupla de argumentos posicionales o un diccionario de argumentos de palabras clave de cualquier longitud. Esto lo convierte en un decorador general que puede decorar una función que tenga cualquier número de argumentos.
Decoradores encadenados
En términos más simples, encadenar decoradores significa decorar una función con múltiples decoradores.
Ejemplo:
Python3
gimp guardar como jpeg
# code for testing decorator chaining> def> decor1(func):> >def> inner():> >x>=> func()> >return> x>*> x> >return> inner> def> decor(func):> >def> inner():> >x>=> func()> >return> 2> *> x> >return> inner> @decor1> @decor> def> num():> >return> 10> @decor> @decor1> def> num2():> >return> 10> > print>(num())> print>(num2())> |
>
>
Producción:
400 200>
El ejemplo anterior es similar a llamar a la función como:
decor1(decor(num)) decor(decor1(num2))>