装饰器补充和递归函数

多层语法糖问题

我们在写代码时可能会遇到同一个函数用多个语法糖来装饰,那么他们之间的关系是什么,怎么执行的就需要看一下下面这段代码了

def outter1(func1):  # 第一步  # 14.outter1(wrapper2)
    print('加载了outter1')  # 15.打印'加载了outter1'
    def wrapper1(*args, **kwargs):  # 16.  # 19.执行
        print('执行了wrapper1')  # 20.打印'执行了wrapper1'
        res1 = func1(*args, **kwargs)  # 21.遇到赋值符号先看右边,此时func1为wrapper2,所以执行wrapper2函数
        return res1
    return wrapper1  # 17.返回值wrapper1被变量名index接收

def outter2(func2):  # 第二步  # 第十步 outter2(wrapper3)
    print('加载了outter2')  # 11.打印'加载了outter2'
    def wrapper2(*args, **kwargs):  # 12.  # 22.执行
        print('执行了wrapper2')  # 23.打印'执行了wrapper2'
        res2 = func2(*args, **kwargs)  # 24. 执行func2函数也就是wrapper3函数
        return res2
    return wrapper2  #  13.返回值wrapper2

def outter3(func3):  # 第三步  # 第六步  outter3(index)
    print('加载了outter3')  # 第七步,打印'加载了outter3'
    def wrapper3(*args, **kwargs):  # 第八步  # 25.执行
        print('执行了wrapper3')  # 26.打印'执行了wrapper3'
        res3 = func3(*args, **kwargs)  # 27.执行func3函数,因为func3接收得是真正的index函数,所以执行真正的index函数
        return res3
    return wrapper3  # 第九步 返回值为wrapper3


@outter1  #outter1(wrapper2) 返回值为wrapper1被变量名index接收
@outter2  # outter2(wrapper3) 返回值为wrapper2,往上传
@outter3  # outter(index) 返回值为wrapper3,往上传
def index():  # 第四步
    print('from index')  # 28.打印'from index'
    
index()  # 第五步执行index函数,先找到函数上面的语法糖然后一步一步往上找
# 18.此时执行index()就是执行wrapper1()

总结:
    多层语法糖的加载顺序是从下往上,每次执行之后如果上面还有语法糖则直接将返回的函数名传给上面的语法糖

有参装饰器

我们之前学的装饰器都是无参装饰器,当我们写的装饰器中需要额外的参数时就要用有参装饰器,但因为原本的装饰器无法改动,所以就在原本的装饰器外面再套一层函数

def outter(a):
    def outer(func_name):
        def inner(*args, **kwargs):
            res = func_name(*args, **kwargs)
            return res
        return inner
    return outer
写成语法糖就是
@outter(a)  # 函数名加括号优先级最高,所以先执行outter(a)然后将返回值返回来再执行语法糖的操作
def index():
    print('from index')

ps:

​ 我们在大多数情况下使用的都是无参装饰器,有参装饰器用到的很少

装饰器修复技术

此技术对于装饰器没有什么作用,仅仅只是让装饰器从内到外都更加逼真

def outer(func):
    def inner(*args, **kwargs):
        '''我不是老虎'''
        res = func(*args, **kwargs)
        return res
    return inner

def index():
    '''12345,上山打老虎'''
    pass
'''未经过装饰器装饰的'''
help(index)  # index() 12345,上山打老虎
print(index)  # <function index at 0x000001EFD7427160>  index指向的内存地址

'''经过装饰器装饰的'''
help(index)  # inner(*args, **kwargs)   我不是老虎
print(index)  # <function outer.<locals>.inner at 0x0000024C0D3E78B0>

下面我们给装饰器做一下修复
from functools import wraps
def outer(func):
    @wraps(func)
    def inner(*args, **kwargs):
        '''我不是老虎'''
        res = func(*args, **kwargs)
        return res
    return inner

此时我们再来看一下
@outer
def index():
    '''12345,上山打老虎'''
    pass
help(index)  # index()   12345,上山打老虎
   
print(index)  # <function index at 0x000001E7B76C78B0>


# help为查看说明

递归函数

1.函数直接或者简介的调用自己
2.函数的每一次调用都要比上一次更加简单,并且要有一个明确的结束条件
'''直接调用'''
def index():
    print(1)
    index()
    
index()
'''间接调用'''
def index():
    print(1)
    func()
def func():
    print(2)
    index()
    
index()
# 像上面的函数写完以后可以正常运行,但是运行到一半会直接报错,这是因为python解释器添加的安全措施,防止内存溢出
'''正确的递归函数应该长这样'''
def get_age(n):
        if n == 1:
            return 18
        return get_age(n-1) + 2
    res = get_age(5)
    print(res)

作业

# 编写一个用户认证装饰器
#   函数:register login transfer withdraw
#   基本要求
#    	 执行每个函数的时候必须先校验身份 eg: jason 123
#   拔高练习(有点难度)
#    	 执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
#   提示:全局变量 记录当前用户是否认证
a = False
b = 1
username_list = {'1':{'name': 'jack', 'pwd': '123'}}
def outter(b):
    def outer(func):
        def inner(*args, **kwargs):
            global a
            if a:
                res = func(*args, **kwargs)
                return res
            name = input('请输入用户名:')
            pwd = input('请输入密码:')
            if b == 1:
                if name == 'jason' and pwd == '123':
                    res = func(*args, **kwargs)
                    # a = True
                    return res
                else:
                    print('用户名密码错误')
            elif b == 2:
                with open(r'D:\b.txt', 'r', encoding='utf8') as f1:
                    for i in f1:
                        name1, age1 = i.split('|')
                        if name == name1 and pwd == age1.strip('\n'):
                            res = func(*args, **kwargs)
                            # a = True
                            return res
                    else:
                            print('用户名密码错误')
            elif b == 3:
                for i in username_list:
                    name_list = username_list.get(i)
                    if name == name_list.get('name') and pwd == name_list.get('pwd'):
                        res = func(*args, **kwargs)
                        # a = True
                        return res
                else:
                        print('用户名密码错误')


        return inner
    return outer



@outter(1)
def register():
    print('注册成功')


@outter(2)
def login():
    print('登录成功')


@outter(3)
def transfer():
    print('转账成功')


@outter(3)
def withdraw():
    print('提现成功')


attes_list = {
    '1': register,
    '2': login,
    '3': transfer,
    '4': withdraw
}

while True:
    print('1.注册功能\n2.登录功能\n3.转账功能\n4.提现功能')
    choice = input('请键入您要选择的功能:').strip()
    if choice in attes_list:
        attes1 = attes_list.get(choice)
        attes1()


posted on 2023-04-04 21:01  zyg111  阅读(33)  评论(0)    收藏  举报