Python デコレータについての話

Pythonではデコレータがよく使われます. 次に私が書いたデコレータを紹介します.デコレータはパラメータなしのデコレータとパラメータありのデコレータ
に分かれます.デコレータは主にクロージャの考え方を使います.

1. パラメータデコレータなし

def wrapper(func):
    """
    定义一个装饰器函数
    :param func:
    :return:
    """
    print("this is wrapper.")  # debug时会发现,这一条语句是使用装饰器时就执行了

    def _wrap(*args, **kwargs):
        """
        定义一个函数,作为装饰器函数的返回值
        :param args:
        :param kwargs:
        :return:
        """
        print("this is _wrap.")  # debug时会发现,这一条语句是调用呗装饰器装饰的函数时执行了
        # 执行功能函数
        return func(*args, **kwargs)

    # 返回一个函数(本质是返回该函数的地址)
    # 使用装饰器后,func传入进来,返回后外部获取的就是_wrap这个函数了
    return _wrap


@wrapper  # 装饰器装饰
def func(*args, **kwargs):
    """

    :param args:
    :param kwargs:
    :return:
    """
    print(f"This is a test function. args:{
      
      args};kwargs:{
      
      kwargs}")


func(1, 2, 3, x=4, y=5)

操作結果:

this is wrapper.
this is _wrap.
This is a test function. args:(1, 2, 3);kwargs:{
    
    'x': 4, 'y': 5}

2.パラメータデコレータがある

デコレータが引数なしデコレータで定義されている場合、仮パラメータはデコレータ関数のみにすることができ、他のパラメータは渡すことができないことがわかります
。次の要件があるとします。ログイン失敗を達成するにはデコレータを使用します。 n回繰り返してログアウト(例:QQPC版 ログイン成功後、ネットワーク切断後、ログイン成功するまで数分間隔で再ログイン)

import random


def loginCheck(count=1):
    """
    一个有参装饰器,这一层函数主要是为了提前接收需要使用除了函数之外的参数
    :param count:
    :return:
    """
    if count < 1:
        count = 1

    def wrapper(func):
        """
        定义一个无参装饰器,内部使用上一层有参装饰器接收的参数来实现功能
        :param func:
        :return:
        """

        def _wrap(*args, **kwargs):
            respond = None
            for i in range(count):
                print(f"第{
      
      i}次登陆", end=";")
                respond = func(*args, **kwargs)
                # 如果成功了就直接返回该值,哪怕是最后返回该值就会使用
                if respond:
                    print("登陆成功.")
                    return respond

                print("登陆失败")

            else:
                # for循环正常执行结束就说明没有登陆成功,返回的也应该是func的返回值
                return respond

        # 返回实现的函数
        return _wrap

    # 返回无参装饰器
    return wrapper


@loginCheck(10)  # 调用有参装饰器
def login(*args, **kwargs):
    # print(f"*args:{args}, **kwargs:{kwargs}")
    n = random.randint(-10, 10)
    if n > 0:
        return True
    else:
        return False


login()

実行結果 (ランダム、複数回実行可能):

0次登陆;登陆失败
第1次登陆;登陆失败
第2次登陆;登陆失败
第3次登陆;登陆失败
第4次登陆;登陆成功.

注: これは、たとえば、ログインが成功したかどうかを確認するためにこの方法を使用するものであり、スプレーしないでください。

パラメータ化されたデコレータが、デコレータが受け取るべきパラメータを受け取るために、パラメータなしのデコレータの外側に関数の層を追加すること簡単にわかります。

3、functoolsインポートラップから

なぜラップを使用するのでしょうか?
各関数には 2 つの属性があります。
name : 戻り関数の名前
doc : 戻り関数のコメント部分です。
デコレータで修飾された関数のこれら 2 つの属性は、デコレータのコンテンツになります。これら 2 つの属性は、デコレータ。返されるものはデコレータです。これら 2 つのプロパティが元の関数のプロパティを返すようにしたい場合は、functiontools でラップ デコレータを使用する必要があります。使用方法は次のとおりです。

from functools import wraps


# ======================wraps========================#
# 每个函数都有自己的属性,使用装饰器之后,就相当于变了属性
# 使用functools.wraps可以让装饰器的属性和原函数一样
# ======================wraps========================#


def wrapper1(func):
    """
    a test wrapper
    :param func:
    :return:
    """
    print("一个普通的无参装饰器")

    def _wrapper(*args, **kwargs):
        """
        a test _wrapper
        :param args:
        :param kwargs:
        :return:
        """
        func(*args, **kwargs)

    return _wrapper


def wrapper2(func):
    """
    a test wrapper with wraps
    :param func:
    :return:
    """
    print("使用wraps后的无参装饰器")

    @wraps(func)
    def _wrapper(*args, **kwargs):
        """
        a test _wrapper
        :param args:
        :param kwargs:
        :return:
        """
        func(*args, **kwargs)

    return _wrapper


def func1(*args, **kwargs):
    """
    a test function1
    :param args:
    :param kwargs:
    :return:
    """
    print(f"this is a function. args:{
      
      args}; kwargs:{
      
      kwargs}")


@wrapper1
def func2(*args, **kwargs):
    """
    a test function2
    :param args:
    :param kwargs:
    :return:
    """
    print(f"this is a function. args:{
      
      args}; kwargs:{
      
      kwargs}")


@wrapper2
def func3(*args, **kwargs):
    """
    a test function3
    :param args:
    :param kwargs:
    :return:
    """
    print(f"this is a function. args:{
      
      args}; kwargs:{
      
      kwargs}")


# 普通函数
print(func1.__name__)
print(func1.__doc__)

# 使用普通的无参装饰器后的效果
print(func2.__name__)
print(func2.__doc__)

# 使用wraps的无参装饰器的效果
print(func3.__name__)
print(func3.__doc__)

操作結果:

__name__: func1
__doc__:
 
    a test function1
    :param args:
    :param kwargs:
    :return:
    
__name__: _wrapper
__doc__:
 
        a test _wrapper
        :param args:
        :param kwargs:
        :return:
        
__name__: func3
__doc__:
 
    a test function3
    :param args:
    :param kwargs:
    :return:

ラップ後にデコレーターで修飾された関数の name 属性と doc 属性が、元の関数と一致していることがわかります。

おすすめ

転載: blog.csdn.net/weixin_50727642/article/details/128750108