Python“三大器”之装饰器2

python学习网 2020-10-12 18:52:02

装饰器

1、叠加装饰器

(1)什么是叠加装饰器

  在同一个被装饰对象中,添加多个装饰器并执行

(2)为什么要使用叠加装饰器

  不使用叠加装饰器会导致代码冗余,结构不清晰,可扩展性差,所以最好每一个新的功能都应该写一个新的装饰器

(3)怎么使用叠加装饰器

  使用方式:

 

    @装饰1

    @装饰2

    @装饰3

    def 被装饰对象():

      pass

 

例子1:

  我的需求:为被装饰对象,添加统计与登录认证功能

import time
user_info = {
    "user": None
}

# 登陆功能
def login():
    username = input("请输入您的账户:").strip()
    password = input("请输入您的密码:").strip()
    with open("dir/passwd.txt", "r", encoding="utf-8") as f:    # 我在同级目录下创建了一个dir目录,然后在目录下创建了一个passwd的文本文档,里面内容为tank:123,然后回车另起一行保存
        info = f.readline().strip("\n").split(":")
        name, pwd = info
        if username == name and password == pwd:
            print("登陆成功...")
            user_info["user"] = username
        else:
            print("登录失败...")

# 登录认证装饰器
def login_auth(func):
    def inner1(*args, **kwargs):
        # 登录认证功能
        if user_info.get("user"):
            res = func(*args, **kwargs)
            return res
        else:
            login()
            return func(*args, **kwargs)    # 无论inner1中出现任何判断,最后都要返回“调用后的被装饰对象”:func(*args, **kwargs)
    return inner1
##### 注意:登陆这里无论inner1中出现任何判断,最后都要返回“调用后的被装饰对象”:func(*args, **kwargs)

# 统计时间装饰器
def time_record(func):
    def inner2(*args, **kwargs):
        print("开始统计...")
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print(f"消耗时间为{end_time - start_time}")
        return res
    return inner2

# 装饰顺序:先装饰time_record,再装饰login_auth
@login_auth    # inner1 = login_auth(inner2)
@time_record     # inner2 = time_record(download_movie)
def download_movie():
    print("电影开始下载...")
    time.sleep(3)
    print("电影下载完成!")
    return "gtwz.mp4"


# 执行顺序:先执行login_auth,再执行time_record
# 只统计下载电影的时间
login()    # 先调用用户登录,模拟用户已登录
download_movie()

注意:装饰器在调用被装饰对象时才会执行添加的功能

  装饰的顺序:由下到上

  执行的顺序:由上到下

 

  附上图解:

 

例子2:通过例子看到执行过程:

def wrapper1(func1):
    def inner1(*args, **kwargs):
        print("1-----start")
        # 被装饰对象在调用时,如果还有其他装饰器,会先执行其他装饰器中的inner
        # 下一步执行inner2
        res = func1(*args, **kwargs)
        print("1-----end")
        return res
    return inner1

def wrapper2(func2):
    def inner2(*args, **kwargs):
        print("2-----start")
        # 被装饰对象在调用时,如果还有其他装饰器,会先执行其他装饰器中的inner
        # 下一步执行inner3
        res = func2(*args, **kwargs)
        print("2-----end")
        return res
    return inner2

def wrapper3(func3):
    def inner3(*args, **kwargs):
        print("3-----start")
        # 被装饰对象在调用时,没有其他装饰器
        # 下一步执行index
        res = func3(*args, **kwargs)
        print("3-----end")
        return res
    return inner3


@wrapper1    # inner1 = wrapper1(inner2)
@wrapper2    # inner2 = wrapper2(inner3)
@wrapper3    # inner3 = wrapper3(index)
# 被装饰对象
def index():
    print("hello")


"""
装饰顺序:
    从下到上
执行顺序:
    从上到下
    
本例子的执行顺序:
    inner1()
    inner2()
    inner3()
    index()
    inner3的res
    inner2的res
    inner1的res
"""

 

 

2、无参装饰器和有参装饰器

(1)无参装饰器

  在被装饰对象装饰时,没有传参数的装饰器


    @wrapper1
    @wrapper2
    @wrapper3


  无参装饰器模板:

# 无参装饰器模板:
def wrapper(func):
    def inner(*args, **kwargs):
        # 添加代码块功能
        res = func(*args, **kwargs)
        # 添加代码块功能
        return res
    return inner

 

(2)有参装饰器

  有参装饰器:在某些时候,需要给用户的权限进行分类

    @wrapper1(参数1)
    @wrapper2(参数2)
    @wrapper3(参数3)

  有参装饰器模板:

# 有参装饰器模板:
def outer(para):    # 传入的para参数是用在inner()内部函数使用
    def wrapper(func):
        def inner(*args, **kwargs):
            if para == "":  # 功能1
                # 添加调用前的功能代码块1
                res = func(*args, **kwargs)
                # 添加调用后的功能代码块1
                return res
            elif para == "":  # 功能2
                # 添加调用前的功能代码块2
                res = func(*args, **kwargs)
                # 添加调用后的功能代码块2
                return res
            else:  # 功能3
                # 添加调用前的功能代码块3
                res = func(*args, **kwargs)
                # 添加调用后的功能代码块3
                return res
            # 无论inner中出现任何判断,最后都要返回“调用后的被装饰对象”:func(*args, **kwargs)
        return inner
    return wrapper

 

例1:可通过传参查看用户权限/功能

def user_auth(user_role):
    def wrapper(func):
        def inner(*args, **kwargs):
            if user_role == "SVIP":
                # 添加svip的权限/功能
                print(user_role)
                res = func(*args, **kwargs)
                return res
            elif user_role == "VIP":
                # 添加vip的权限/功能
                print(user_role)
                res = func(*args, **kwargs)
                return res
        return inner
    return wrapper


@user_auth("VIP")
def index():
    pass

index()

 

 

3、wraps修复(了解)

  wraps是一个修复工具,修复的是被装饰对象的空间

functools import wraps

def wrapper(func):
    @wraps(func)    # 修改名称空间:inner ---> func
    def inner(*args, **kwargs):
        """
        这里是装饰器
        :param args:
        :param kwargs:
        :return:
        """
        res = func(*args, **kwargs)
        return res
    return inner


def index():
    """
    这里是被装饰对象
    :return:
    """
    pass

print(index)
print(index.__doc__)
阅读(2499) 评论(0)