Python函数装饰器多层语法糖

文章目录

  • 一、多层语法糖
      • 1. 什么是多层语法糖
      • 2. 多层语法糖的用法
  • 二、装饰器的修复技术
  • 三、有参装饰器

在上一篇文章中我们讲到了Python函数装饰器的语法糖,这次我们来了解多层语法糖以及装饰器的修复技术和,有参装饰器

一、多层语法糖

1. 什么是多层语法糖

多层语法糖是指在单个源代码函数名上方添加了多个语法糖,使这段源代码函数体具备多个功能

2. 多层语法糖的用法

def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outter2(func2):
    print('加载了outter2')
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3

@outter1
@outter2
@outter3
def index():
    print('from index')

index()

# 执行结果:
# 注意不运行index()函数,直接执行脚本文件,也会打印最上面这3行话的!!!
# 不要理解为,只有运行被装饰的函数index时,装饰器函数outter才会运行!!!
#   @outter
#   def index(): pass
#   当代码加载到这的时候,就已经自动运行该代码 index = outter(index)
#   也就是运行装饰器函数 outter()  了!!!
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index

-------------------------------------------

# 多层语法糖   加载顺序由下往上
# 执行顺序 准确讲并不是由上往下!!!

--------------------------------------------
# 执行的顺序如下:
def outter1(func1):
    print('加载了outter1')

    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func2(*args, **kwargs)  # func1 实际上是wrapper2函数名
        print('执行wrapper1 结束了')
        return res1

    return wrapper1


def outter2(func2):
    print('加载了outter2')

    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)  # func2 实际上是wrapper3函数名
        print('执行wrapper2 结束了')
        return res2

    return wrapper2


def outter3(func3):
    print('加载了outter3')

    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)  # func3 才是真正的被装饰的函数名
        print('执行wrapper3 结束了')
        return res3

    return wrapper3


@outter1
@outter2
@outter3
def index():
    print('from index')


# 注意装饰器函数 与 装饰器函数的内层函数的区别,@装饰器函数名 
# 装饰器函数就已经被传参并运行了!!!
# 但是此时 装饰器的内层函数 并没有被运行!!!

# index() 函数还没调用前就已经先执行如下步骤了
# 1  先运行outer3(index函数名),并把返回值wrapper3函数名往上一层的装饰器函数里面传
# 2  再运行outer2(wrapper3函数名),并把返回值wrapper2函数名往上一层的装饰器函数里面传
# 3  由于outter1装饰器函数上面没有装饰器函数了,所以执行 index=outer1(wrapper2)
# 4  运行完outer1(wrapper2),把返回值wrapper1,赋值给了index
# 5  所以也就是在还没有运行被装饰的函数前,这4步已经走完了

# 6  最后当我们运行被装饰的函数index()时,
#    实际上就是开始从最外面的内层函数wrapper1() 开始执行了

# 7  由于装饰器函数已经从下往上加载过一遍了,每一个装饰器函数都已经被传参并运行过了
# 8  所以最外面的内层函数wrapper1() 开始执行时,func1是有明确值的,就是wrapper2函数名
# 9  同理func2也是有明确值的,就是wrapper3函数名
#    同理func3也是有明确值的,就是被装饰的函数名

index()  # 执行的结果如下:

加载了outter3
加载了outter2
加载了outter1   # 注意不运行index()函数,直接执行脚本文件,也会打印上面这3行话的!!!
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
执行wrapper3 结束了
执行wrapper2 结束了
执行wrapper1 结束了

二、装饰器的修复技术

作用就是在装了装饰器后,调用函数体代码运行时,查看函数体代码运行时,返回值变成了正在的被装饰函数体代码运行后的返回值,欺骗性更高了。

def index():
"""index函数 非常的牛"""
    pass

help(index)    # help方法会给你打印出  该函数的名字,以及该函数里面的注释!!!
help(len)    # 这个就是查看  该len函数或者类的名字,以及该len函数或类里面的注释

-------------------------------------------------------

from functools import wraps   # 1 就加两行代码

def outer(func_name):

    # 2 这个装饰器一写,打印被装饰函数的函数名,打出的就真的是被装饰函数名了
    @wraps(func_name)
    def inner(*args, **kwargs):
        """我是inner 我擅长让人蒙蔽"""
        res = func_name(*args, **kwargs)
        return res

    wrapper.__name__ = func.__name__    # 3
  # 这行代码的作用是将被装饰的函数的名称赋值给装饰器内部定义的包装函数(wrapper)的名称。
   # 这样做的目的是保留被装饰函数的原始名称,这在调试和日志记录等情况下非常有用。
    return inner




@outer
def func():
    """我是真正的func 我很强大 我很牛 我很聪明"""
    pass

help(func)  # 不用@wraps(func_name)  打印的函数名是inner
            # 用了 @wraps(func_name)   打印的函数名,就又变成了原函数名了

func()  # 还是正常执行装饰器函数的内层函数 inner

# 这三行装饰器代码的目的就是让装饰器,装的更像一点,被装饰的函数运行时,
# 还是执行的装饰器函数的内层函数 inner

三、有参装饰器

就是在原来无参装饰器的基础上再套一层自定义函数,这时候就可以在最外层的的装饰器函数的括号里进行传参,不会影响被装饰函数体代码的正常运行。

def outter(source_type, *args1, **kwargs1):
    def login_auth(func):  # 参数个数只能有一个
        def auth(*args, **kwargs): #
            username = input('username:>>>').strip()
            password = input('password:>>>').strip()
            # 2. 比较用户名和密码
            """
                1. 文件中获取用户名和密码
                2. 从MySQL中获取用户名和密码
                3. 从oracle中获取用户名和密码
                4. 从postgresql中获取用户名和密码
            """
            # print(a, b, c, d, e, f)
            if source_type == 'file':
                print('文件中获取用户名和密码')
            elif source_type == 'mysql':
                print('从MySQL中获取用户名和密码')
            elif source_type == 'oracle':
                print('从oracle中获取用户名和密码')
            elif source_type == 'postgresql':
                print('从postgresql中获取用户名和密码')

            if username == 'jerry' and password == '123':
                # 执行函数
                print('登录成功')
                func(*args, **kwargs)
            else:
                print('用户名或者密码错误')
        return auth
    return login_auth

@outter('file', 1, 2, 3, 4, 5, 6) # login_auth(home, file)
# @login_auth # login_auth(home, file)
def home():
    pass

home()

你可能感兴趣的:(python,开发语言)