Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> python

Decoradores de pitón

Decoradores de Python

Un decorador toma una función, agrega alguna funcionalidad y la devuelve. En este tutorial, aprenderá cómo puede crear un decorador y por qué debería usarlo.

Video:@Decorators en Python

Decoradores en Python

Python tiene una característica interesante llamada decoradores para agregar funcionalidad a un código existente.

Esto también se llama metaprogramación porque una parte del programa intenta modificar otra parte del programa en tiempo de compilación.


Requisitos previos para aprender decoradores

Para entender acerca de los decoradores, primero debemos saber algunas cosas básicas en Python.

Debemos sentirnos cómodos con el hecho de que todo en Python (¡Sí! Incluso las clases) son objetos. Los nombres que definimos son simplemente identificadores vinculados a estos objetos. Las funciones no son una excepción, también son objetos (con atributos). Se pueden vincular varios nombres diferentes al mismo objeto de función.

Aquí hay un ejemplo.

def first(msg):
    print(msg)


first("Hello")

second = first
second("Hello")

Salida

Hello
Hello

Cuando ejecuta el código, ambas funciones first y second dar la misma salida. Aquí, los nombres first y second se refieren al mismo objeto de función.

Ahora las cosas empiezan a ponerse más raras.

Las funciones se pueden pasar como argumentos a otra función.

Si ha utilizado funciones como map , filter y reduce en Python, entonces ya sabes sobre esto.

Las funciones que toman otras funciones como argumentos también se denominan funciones de orden superior. . Aquí hay un ejemplo de tal función.

def inc(x):
    return x + 1


def dec(x):
    return x - 1


def operate(func, x):
    result = func(x)
    return result

Invocamos la función de la siguiente manera.

>>> operate(inc,3)
4
>>> operate(dec,3)
2

Además, una función puede devolver otra función.

def is_called():
    def is_returned():
        print("Hello")
    return is_returned


new = is_called()

# Outputs "Hello"
new()

Salida

Hello

Aquí, is_returned() es una función anidada que se define y devuelve cada vez que llamamos a is_called() .

Finalmente, debemos saber sobre Closures en Python.


Volviendo a Decoradores

Las funciones y los métodos se denominan invocables como se les puede llamar.

De hecho, cualquier objeto que implemente el __call__() especial método se denomina invocable. Entonces, en el sentido más básico, un decorador es un invocable que devuelve un invocable.

Básicamente, un decorador toma una función, agrega alguna funcionalidad y la devuelve.

def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner


def ordinary():
    print("I am ordinary")

Cuando ejecuta los siguientes códigos en shell,

>>> ordinary()
I am ordinary

>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary

En el ejemplo que se muestra arriba, make_pretty() es decorador En el paso de asignación:

pretty = make_pretty(ordinary)

La función ordinary() se decoró y la función devuelta recibió el nombre pretty .

Podemos ver que la función de decorador agregó algunas funciones nuevas a la función original. Esto es similar a empacar un regalo. El decorador actúa como envoltorio. La naturaleza del objeto que se decoró (regalo real en el interior) no se altera. Pero ahora, se ve bonito (desde que se decoró).

Generalmente, decoramos una función y la reasignamos como,

ordinary = make_pretty(ordinary).

Esta es una construcción común y por esta razón, Python tiene una sintaxis para simplificar esto.

Podemos usar el @ símbolo junto con el nombre de la función decoradora y colóquelo encima de la definición de la función a decorar. Por ejemplo,

@make_pretty
def ordinary():
    print("I am ordinary")

es equivalente a

def ordinary():
    print("I am ordinary")
ordinary = make_pretty(ordinary)

Esto es solo un azúcar sintáctico para implementar decoradores.


Funciones decorativas con parámetros

El decorador anterior era simple y solo funcionaba con funciones que no tenían ningún parámetro. ¿Qué pasaría si tuviéramos funciones que tomaran parámetros como:

def divide(a, b):
    return a/b

Esta función tiene dos parámetros, a y b . Sabemos que dará error si pasamos b como 0.

>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero

Ahora hagamos que un decorador verifique este caso que causará el error.

def smart_divide(func):
    def inner(a, b):
        print("I am going to divide", a, "and", b)
        if b == 0:
            print("Whoops! cannot divide")
            return

        return func(a, b)
    return inner


@smart_divide
def divide(a, b):
    print(a/b)

Esta nueva implementación devolverá None si surge la condición de error.

>>> divide(2,5)
I am going to divide 2 and 5
0.4

>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide

De esta manera podemos decorar funciones que toman parámetros.

Un observador entusiasta notará que los parámetros del inner() anidado La función dentro del decorador es la misma que los parámetros de las funciones que decora. Teniendo esto en cuenta, ahora podemos crear decoradores generales que funcionen con cualquier cantidad de parámetros.

En Python, esta magia se hace como function(*args, **kwargs) . De esta forma, args será la tupla de argumentos posicionales y kwargs será el diccionario de argumentos de palabras clave. Un ejemplo de tal decorador será:

def works_for_all(func):
    def inner(*args, **kwargs):
        print("I can decorate any function")
        return func(*args, **kwargs)
    return inner

Encadenamiento de decoradores en Python

Se pueden encadenar varios decoradores en Python.

Es decir, una función se puede decorar varias veces con decoradores diferentes (o iguales). Simplemente colocamos los decoradores encima de la función deseada.

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner


def percent(func):
    def inner(*args, **kwargs):
        print("%" * 30)
        func(*args, **kwargs)
        print("%" * 30)
    return inner


@star
@percent
def printer(msg):
    print(msg)


printer("Hello")

Salida

******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Hello
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************

La sintaxis anterior de,

@star
@percent
def printer(msg):
    print(msg)

es equivalente a

def printer(msg):
    print(msg)
printer = star(percent(printer))

El orden en el que encadenamos a los decoradores es importante. Si hubiéramos invertido el orden como,

@percent
@star
def printer(msg):
    print(msg)

La salida sería:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
Hello
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

python

  1. Tipos de datos de Python
  2. Operadores de Python
  3. Declaración de paso de Python
  4. Argumentos de la función de Python
  5. Python Anónimo/Función Lambda
  6. Funciones Python Lambda con EJEMPLOS
  7. Función Python abs():Ejemplos de valores absolutos
  8. Función Python round() con EJEMPLOS
  9. Python range() Función:Flotante, Lista, Para ejemplos de bucle
  10. Función Python map() con EJEMPLOS
  11. Tutorial de Rendimiento en Python:Generador y Rendimiento vs Ejemplo de Retorno