Los 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 serán útiles para aprender 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 de objeto.
- Puede almacenar la función en una variable.
- Puede pasar la función como un 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 saludar toma otra función como parámetro (gritar y susurrar en este caso). La función pasada como argumento se llama dentro de la función saludar.
Ejemplo 3: Devolver funciones desde otra función.
Python3
# 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, hemos creado una función dentro de otra función y luego hemos devuelto la función creada dentro.
Los tres ejemplos anteriores representan los conceptos importantes que se necesitan para comprender a los decoradores. Después de revisarlos, profundicemos ahora en los decoradores.
Decoradores
Como se indicó anteriormente, los decoradores se utilizan para modificar el comportamiento de una función o clase. En Decorators, 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á un 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 la «función_a_usar».
Pasemos a otro ejemplo en el que podemos averiguar 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 necesite 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 con cualquier número de argumentos.
Enstringmiento de decoradores
En términos más simples, enstringr decoradores significa decorar una función con múltiples decoradores.
Ejemplo:
Python3
# 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 print(num())
Producción:
400
El ejemplo anterior es similar a llamar a la función como –
decor1(decor(num))
Publicación traducida automáticamente
Artículo escrito por Sheetansh kumar y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA