Un artículo para comprender todo el uso del decorador Python

01. Decorador de azúcar sintáctico

Si ha estado en contacto con Python por un tiempo, debe estar familiarizado con el símbolo @. Sí, el símbolo @ es azúcar sintáctico para decoradores.

Se coloca donde una función comienza a definirse, y se usa en la cabeza de esta función como un sombrero. Vincularse a esta función. Cuando llamamos a esta función, lo primero no es ejecutar esta función, sino pasar esta función como un parámetro a este sombrero en la parte superior de nuestra cabeza. Este sombrero se llama función decorativa o decorador.

¿Tiene que preguntarme qué función puede lograr el decorador? Solo puedo decir que el decorador es tan poderoso como tu cerebro.

El método de usar el decorador es muy fijo:

Primero defina una función decorativa (sombrero) (también se puede implementar con clases y funciones parciales)

  • Luego defina su función comercial o clase (persona)
  • Finalmente pon este sombrero en la cabeza de esta persona

Hay muchos usos simples de decoradores, aquí hay dos comunes.

  • Impresora de registro
  • Temporizador de tiempo

02. Uso inicial: impresora de registro ##

El primero es la impresora de registro.

Funciones realizadas:

Antes de ejecutar la función, primero imprima un registro para informar al host que deseo ejecutar la función.
Después de que se ejecuta la función, no puede darle una palmadita en el culo y salir, pero tenemos un código amable y luego imprimimos una línea de registros para informar al host, he terminado.

# 这是装饰函数
def logger(func):
    def wrapper(*args, **kw):
        print('我准备开始计算:{} 函数了:'.format(func.__name__))

        # 真正执行的是这行。
        func(*args, **kw)

        print('啊哈,我计算完啦。给自己加个鸡腿!!')
    return wrapper

Si mi función comercial es calcular la suma de dos números. Después de escribir, ponle un sombrero directamente.

@logger
def add(x, y):
    print('{} + {} = {}'.format(x, y, x+y))

Entonces vamos a calcular.

add(200, 50)

Ven y mira lo que sale, ¿es mágico?

Estoy listo para comenzar el cálculo: agregar función:

200 + 50 = 250

Ajá, ya terminé. ¡Agréguese una baqueta!

03. Uso inicial: temporizador de tiempo ##

Echemos un vistazo a la
función de temporizador de tiempo : como su nombre indica, es para calcular el tiempo de ejecución de una función.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# 这是装饰函数
def timer(func):
    def wrapper(*args, **kw):
        t1=time.time()
        # 这是函数真正执行的地方
        func(*args, **kw)
        t2=time.time()

        # 计算下时长
        cost_time = t2-t1 
        print("花费时间:{}秒".format(cost_time))
    return wrapper

Supongamos que nuestra función es dormir durante 10 segundos. De esta manera, podemos ver mejor si el tiempo de cálculo es confiable.

import time

@timer
def want_sleep(sleep_time):
    time.sleep(sleep_time)

want_sleep(10)

Echa un vistazo y salida. Realmente son 10 segundos. Realmente malvado! ! !

花费时间:10.0073800086975098

04. Uso avanzado: decorador de funciones con parámetros ##

A través de la simple introducción anterior, probablemente ya haya sentido el encanto mágico de la decoración.

Sin embargo, el uso de decoradores va mucho más allá de esto. Dejaremos claro este punto hoy.

En el ejemplo anterior, el decorador no puede aceptar parámetros. Su uso solo se puede aplicar a algunos escenarios simples. Los decoradores que no pasan parámetros solo pueden ejecutar una lógica fija en la función decorada.

Si tiene experiencia, debe estar en el proyecto con frecuencia y ver algunos decoradores con parámetros.

El decorador en sí es una función, y dado que no se puede llevar como una función, la función de esta función es muy limitada. Solo se puede ejecutar la lógica fija. Esto es indudablemente muy irrazonable. Y si queremos usar los dos contenidos para que sean más o menos iguales, es solo una lógica diferente en algunos lugares. Si no pasamos parámetros, escribiremos dos decoradores. Xiao Ming sintió que era intolerable.

Entonces, ¿cómo implementa el decorador el paso de parámetros? Será más complicado y requerirá dos niveles de anidamiento.

Del mismo modo, tomemos un ejemplo.

Cuando ejecutamos estas dos funciones, diremos una palabra de saludo en función de su nacionalidad.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def american():
    print("我来自中国。")

def chinese():
    print("I am from America.")

Al colocar el decorador en los dos, debe decirle al decorador, qué país es esta persona, y luego el decorador emitirá un juicio y saludará.

Así es como se ve después de usar un sombrero.

@say_hello("china")
def american():
    print("我来自中国。")

@say_hello("america")
def chinese():
    print("I am from America.")

Todo está listo, solo un sombrero. Vamos a definirlo, aquí necesitamos dos niveles de anidamiento.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def say_hello(contry):
    def wrapper(func):
        def deco(*args, **kwargs):
            if contry == "china":
                print("你好!")
            elif contry == "america":
                print('hello.')
            else:
                return

            # 真正执行函数的地方
            func(*args, **kwargs)
        return deco
    return wrapper

Hazlo

american()
print("------------")
chinese()

Mira la salida.

你好!
我来自中国。
------------
hello.
I am from America

emmmm, esto es muy NB. . .

05. Uso avanzado: decorador de clase sin parámetros ##

Los anteriores son todos decoradores basados ​​en funciones. Al leer el código de otras personas, a menudo puede encontrar que también hay decoradores basados ​​en clases.

En función de la implementación del decorador de clase, se deben implementar dos funciones integradas __ call__ y __ init__.
__ init__: Recibir función decorada
__ call__: Implementar lógica de decoración.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class logger(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("[INFO]: the function {func}() is running..."\
            .format(func=self.func.__name__))
        return self.func(*args, **kwargs)

@logger
def say(something):
    print("say {}!".format(something))

say("hello")

Ejecútelo y vea la salida

[INFO]: the function say() is running...
say hello!

06. Uso avanzado: decorador de clase con parámetros ##

En el ejemplo anterior sin parámetros, descubrió que no existe, solo puede imprimir registros de nivel INFO, en circunstancias normales, también necesitamos imprimir ADVERTENCIA DE DEPURACIÓN y otros niveles de registros. Esto requiere pasar parámetros al decorador de clase y asignar un nivel a esta función.

Los decoradores de clase con y sin parámetros son muy diferentes.

__ init__: ya no recibe la función decorada, pero recibe los parámetros entrantes.
__ call__: Recibe la función decorada e implementa la lógica de decoración.

class logger(object):
    def __init__(self, level='INFO'):
        self.level = level

    def __call__(self, func): # 接受函数
        def wrapper(*args, **kwargs):
            print("[{level}]: the function {func}() is running..."\
                .format(level=self.level, func=func.__name__))
            func(*args, **kwargs)
        return wrapper  #返回函数

@logger(level='WARNING')
def say(something):
    print("say {}!".format(something))

say("hello")

Especificamos el nivel de ADVERTENCIA y lo ejecutamos para ver la salida.

[WARNING]: the function say() is running...
say hello!

07. Uso de funciones parciales y clases para implementar decoradores ##

La mayoría de los decoradores se implementan en función de funciones y cierres, pero esta no es la única forma de hacer decoradores.

De hecho, Python solo tiene un requisito para determinar si un objeto puede usarse en forma de decorador (@decorator): el decorador debe ser un objeto "invocable".

Para este objeto invocable, estamos más familiarizados con las funciones.

Además de las funciones, las clases también pueden ser objetos invocables. Siempre que se implemente la función __call__ (se han tocado los cuadros anteriores), también hay funciones parciales que las personas rara vez usan.

A continuación, hablemos sobre cómo usar las clases y las funciones parciales para lograr un decorador distintivo.

Como se muestra a continuación, DelayFunc es una clase que implementa __call__, delay devuelve una función parcial, donde delay puede usarse como decorador. (El siguiente código está tomado del artesano Python: consejos para usar decoradores)

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import time
import functools

class DelayFunc:
    def __init__(self,  duration, func):
        self.duration = duration
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Wait for {self.duration} seconds...')
        time.sleep(self.duration)
        return self.func(*args, **kwargs)

    def eager_call(self, *args, **kwargs):
        print('Call without delay')
        return self.func(*args, **kwargs)

def delay(duration):
    """
    装饰器:推迟某个函数的执行。
    同时提供 .eager_call 方法立即执行
    """
    # 此处为了避免定义额外函数,
    # 直接使用 functools.partial 帮助构造 DelayFunc 实例
    return functools.partial(DelayFunc, duration)

Nuestra función comercial es muy simple, solo agregue

@delay(duration=2)
def add(a, b):
    return a+b

Echa un vistazo al proceso de implementación

>>> add    # 可见 add 变成了 Delay 的实例
<__main__.DelayFunc object at 0x107bd0be0>
>>> 
>>> add(3,5)  # 直接调用实例,进入 __call__
Wait for 2 seconds...
8
>>> 
>>> add.func # 实现实例方法
<function add at 0x107bef1e0>

08. ¿Cómo escribir decoradores que puedan decorar? ##

Al escribir patrones singleton en Python, hay tres formas comunes de escritura. Uno de ellos se implementa con un decorador.

El siguiente es un caso único de la versión decoradora que escribí yo mismo.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
instances = {}

def singleton(cls):
    def get_instance(*args, **kw):
        cls_name = cls.__name__
        print('===== 1 ====')
        if not cls_name in instances:
            print('===== 2 ====')
            instance = cls(*args, **kw)
            instances[cls_name] = instance
        return instances[cls_name]
    return get_instance

@singleton
class User:
    _instance = None

    def __init__(self, name):
        print('===== 3 ====')
        self.name = name

Puede ver que utilizamos la función de decoración singleton para decorar la clase Usuario. No es muy común que los decoradores se usen en las clases, pero mientras esté familiarizado con el proceso de implementación de decoradores, no es difícil implementar decoraciones en las clases. En el ejemplo anterior, el decorador simplemente implementa control sobre la generación de instancias de clase.

El proceso de creación de instancias, puede consultar mi proceso de depuración aquí para comprender.

705 artículos originales publicados · Me gustó 862 · Visitas 1.5 millones +

Supongo que te gusta

Origin blog.csdn.net/sinat_38682860/article/details/105455366
Recomendado
Clasificación