Casos útiles para ilustrar Decorators en python

Un decorador es un tipo especial de función que toma una función y devuelve una función o toma una clase y devuelve una clase. Bueno, puede ser cualquier invocable (es decir, funciones, clases, métodos, ya que pueden llamarse) y puede devolver cualquier cosa, también puede tomar un método. Esto también se llama metaprogramación , ya que una parte del programa intenta modificar otra parte del programa en tiempo de compilación.
Sumerjámonos en los decoradores de python y descubramos qué pueden hacer. Esto no cubrirá los conceptos básicos o los decoradores con parámetros, sino algunos ejemplos útiles para ilustrar el caso.

Consulte el siguiente artículo para obtener los conceptos básicos de los decoradores de Python

Básicamente, un decorador toma un invocable, cualquier objeto que implemente el método especial __call()__se denomina invocable, agrega alguna funcionalidad y devuelve un invocable.

Ejemplo 1:

# Python program to demonstrate
# decorators
  
  
# Creating a decorator
def decorated_func(func):
    def inner():
        print("This is decorated function")
        func()
    return inner()
  
  
def ordinary_func ():
    print("This is ordinary function")
  
decorated = decorated_func(ordinary_func)
decorated

Producción:

This is decorated function
This is ordinary function

En el ejemplo que se muestra arriba, decorated_func()es un decorador. En resumen, un decorador actúa como un envoltorio que envuelve un objeto (no altera el objeto original) y agrega una nueva funcionalidad al objeto original. Esta es una construcción común, por lo que Python tiene una característica de sintaxis (llamada Decorator) para simplificar esto. Por ejemplo,

Este:

@decorated_func
def ordinary_func():
     print("This is ordinary function")

es equivalente a:

def ordinary_func():
    print("This is ordinary function")
decorated = decorated_func(ordinary_func)

Un ejemplo sencillo sería:

Ejemplo 2:
Entrada:

def mul_decorator(func):
    def wrapper(*args, **kwargs):
        print('function', func.__name__, 'called with args - ', /
              args, 'and kwargs - ', kwargs)
        result = func(*args, **kwargs)
        print('function', func.__name__, 'returns', result)
        return result
    return wrapper
  
  
@mul_decorator
def mul(a, b):
    return a * b
mul(3, 3)
mul(3, b = 6)

Producción:

function mul called with args -  (3, 3) and kwargs -  {}
function mul returns 9
function mul called with args -  (3,) and kwargs -  {'b': 6}
function mul returns 18

También puedes usar los empotrados como decoradores

Ejemplo 3:

# func will be func = type(func) -> <class 'function'>
@type
def func(): 
    return 42
  
print(func)
  
# print doesn't return anything, so func == None
@print
def func2(): 
    return 42
  
# Prints None
print(func2)

Producción:

<class 'function'>
<function func2 at 0x7f135f067f28>
None

Puedes reemplazar el objeto decorado con otra cosa

Ejemplo 4:

# Creating a decorator
class function_1:
    def __init__(self, func):
        self.func = func
        self.stats = []
  
    def __call__(self, *args, **kwargs):
        try:
            result = self.func(*args, **kwargs)
        except Exception as e:
            self.stats.append((args, kwargs, e))
            raise e
        else:
            self.stats.append((args, kwargs, result))
            return result
  
    @classmethod
    def function_2(cls, func):
        return cls(func)
  
  
@function_1.function_2
def func(x, y):
    return x / y
  
print(func(6, 2))
  
print(func(x = 6, y = 4))
  
func(5, 0)
print(func.stats)
print(func)

Producción:

3.0
1.5
Traceback (most recent call last):
  File "/home/1ba974e44c61e303979b3ee120b6b066.py", line 29, in 
    func(5, 0)
  File "/home/1ba974e44c61e303979b3ee120b6b066.py", line 11, in __call__
    raise e
  File "/home/1ba974e44c61e303979b3ee120b6b066.py", line 8, in __call__
    result = self.func(*args, **kwargs)
  File "/home/1ba974e44c61e303979b3ee120b6b066.py", line 23, in func
    return x / y
ZeroDivisionError: division by zero

Observe cómo el original "func"fue reemplazado por una instancia de "function_1", que se puede usar de la misma manera que la función original.
Puede crear una relación con otros objetos en el sistema

Ejemplo 5:

def dict_from_func(func):
    return {func.__name__: func}
  
  
activity = {}
  
@activity.update
@dict_from_func
def mul(a, b):
    return a * b
  
  
@activity.update
@dict_from_func
def add(a, b):
    return a + b
  
  
print(mul)
print(activity)
print(activity['mul'](2, 5))

Producción:

None
{'mul': <function mul at 0x7f0d2209fe18>, 
 'add': <function add at 0x7f0d220a2158>}
10

Aquí, en el ejemplo 5, hemos utilizado dict.updateel método como decorador, aunque no esté destinado a ello. Esto es posible porque dict_from_funcdevuelve un dict y dict.updatetoma un dict como argumento.

En realidad, esto:

@activity.update
@dict_from_func
def mul(a, b):
    return a * b

es igual a esto –

def mul(a, b):
    return a * b
mul = activity.update(dict_from_func(mul))

Conclusión

Los decoradores son una característica interesante y sorprendente y se pueden usar para una variedad de propósitos. No es solo «función o clase que toma una función o una clase y devuelve una función o una clase» .

Publicación traducida automáticamente

Artículo escrito por SadanandNerurkar y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *