Talking about python decorators

Decorators are often used in python. Next, let me introduce the decorators I wrote.
Decorators are divided into decorators without parameters and decorators with parameters.
Decorators mainly use the idea of ​​closure.

1. No parameter decorator

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)

operation result:

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

2. There are parameter decorators

It can be found that when the decorator is defined in the no-argument decorator, the formal parameter can only be the decorated function, and other parameters cannot be passed in.
Assume that there is a requirement: use the decorator to achieve login failure after n times and log out (example: QQPC version After the login is successful, it will log in again at intervals of a few minutes after the network is disconnected, until the login is successful)

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()

Running results (random, you can run it several times):

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

Note: This is for example, use this method to check whether the login is successful, do not spray.

It is easy to find that the parameterized decorator is to add a layer of functions outside the parameterless decorator to receive the parameters that the decorator should receive.

3、from functools import wraps

Why use wraps?
Each function has two attributes
name : the name of the return function
doc : the comment part of the return function.
These two attributes of the function decorated with decorators become the content of the decorator. We don’t want these two attributes after using the decorator. The one returned is a decorator. If you want these two properties to return the properties of the original function, you need to use the wraps decorator in functiontools. The usage is as follows:

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__)

operation result:

__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:

You can see that the name and doc attributes of the function decorated with the decorator after wraps are consistent with the original function

Guess you like

Origin blog.csdn.net/weixin_50727642/article/details/128750108