有参装饰器
今日内容
- 多层装饰器
- 有参装饰器
- 递归函数
- 算法之二分法
- 作业
多层装饰器
多成装饰器就是有多个装饰器添加到了被装饰器对象上面
为被装饰器对象添加新功能 而多层装饰器的运行顺序如下:
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 # 可以看成是wrapper2当做参数传入 index = outter1(wrapper2) 所以func1就是wrapper2 # 执行outter1时返回的是wrapper1的内存地址 index现在的内存地址变成了wrapper1 index 就相当于wrapper1 @outter2 # 可以看成是wrapper3当做参数传入 index = outter2(wrapper3) 所以func2就是wrapper3 # 执行outter2时返回的是wrapper2的内存地址 index现在的内存地址变成了wrapper2 所以可以把上面的赋值看成 # wrapper2 = outter2(wrapper3) @outter3 # 就是把index当做参数传入 idnex = outter(被装饰对象函数名:index) 所以func3就是index # 执行outter3函数的时候返回的是wrapper3的内存地址所以index现在绑定的是wrapper3 # wrapper3 = outter(index) def index(): print('from index') index() ''' 所以运行函数index时因为现在index的内存地址为wrapper1所以会先执行wrapper1()函数 然后运行到res1 = func1(*args, **kwargs)因为现在func1的内存地址为wrapper2 所以会执行wrapper2()函数 因为wrapper2中的func2的内存地址为wrapper3 所以会先执行wrapper3()函数 因为wrapper3中的func3的内存地址为index所以执行index()函数执行完并结束 index()函数结束运行时然后就会结束wrapper3函数然后依次往上结束 ''' ''' 所以执行结果为: 加载了outter3 加载了outter2 加载了outter1 执行了wrapper1 执行了wrapper2 执行了wrapper3 from index '''
有参装饰器
有参装饰器就是在原本的装饰器上面在套上一个函数 这样就可以满足原本的装饰器需要几个参数就可以传几个参数
def login_auth(func_name): def inner(*args, **kwargs): res = func_name(*args, **kwargs) return res return inner # 这是之前装饰器的模板 这个模板其实已经接近完美 但是如果现在需要在装饰器里还需要添加参数怎么办? # 就比如现在需要在多个函数前加上用户登入验证 只有登入成功才能执行被装饰对象的函数 # 还要根据不同的数据库验证 def outter(choice): def login_auth(func_name): def inner(*args, **kwargs): username = input('username>>>:').strip() password = input('password>>>:').strip() if choice == '列表': print('基于列表验证') res = func_name(*args, **kwargs) return res elif choice == '字典': print('基于字典验证') res = func_name(*args, **kwargs) return res elif choice == '文件': print('基于文件验证') res = func_name(*args, **kwargs) return res else: print('用户权限不够 无法调用函数') return inner return login_auth @ outter('列表') # index = login_auth(index) def index(): pass index() # 现在装饰器出现了新的参数而如何给这个参数传值呢? # 首先如果在inner函数写上形参的话 解释器就会报错 因为这违反了装饰器的功能 使调用函数时发生改变了 # 如果在login_auth函数写上参数的话 也是会报错的 因为这违反了语法糖的语法 # 所以我们只能使用闭包函数传参在装饰器外面在套上一个函数 这样装饰器想要多少个参数多可以传给它为了
递归函数
递归函数的意思就是执行函数代码时直接或间接调用了自己称之为递归函数
1.直接调用
def func(i): print(i) func(i) func(1) ''' 在一个函数中直接调用自己的就是直接调用 像上方函数的意思就是一直打印1 直到报错 因为python有最大递归深度 '''
2.间接调用
def func(): print('form func') index() def index(): print('form index') func() func() ''' 像上方所写的代码在一个函数A中调用了函数B 而函数B中的代码又调用了函数A 就是间接调用 不过也会报错 '''
不管是直接调用还是间接调用都是有最大递归深度的超过就会报错
而官方给出的最大递归深度的1000 不过通过代码测试也有可能会得出998、997
import sys print(sys.getrecursionlimit()) # 1000 获取递归最大次数 sys.setrecursionlimit(2000) # 自定义最大次数 print(sys.getrecursionlimit()) # 2000
3.递归函数的应用
递归函数的引用场景:
1.递推:一层一层的网下寻找真正的答案
2.回溯:根据一致答案倒推会答案
递归函数:
1.递归函数每次的调用都必须比上一次简单
2.递归函数最后必须要有一个明确的结束条件
必须满足以上两个条件才能被称之为递归函数
就比如:
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]] # 然后依次取出里面所有的值 # 首先我可以用到for循环 for i in l: if isinstance(i, int): # isinstance就是判断一个数据值是不是某个数据类型 print(i) # 因为for循环是一个一个取值取到第二个的时候是一个列表所以还要for循环 for j in i: if isinstance(j, int): print(j) for k in j: if isinstance(k, int): print(k) ... # 这样一直往复下就可以取出所有的值 但是这样写的时候就会发现重复的代码会变多我们可以把重复的代码封装成函数即可 def get_num(l): for i in l: if isinstance(i, int): print(i) else: get_num(i) get_num(l1) # 这样当我们使用递归函数的时候就可以免去复杂的代码编写是代码变得简单
算法之二分法
算法就是解决问题的一些方法
是一些数学公式通过代码编写出来
有时候替我们解决一些问题
算法没有最终解只有一直在优化与完善 很少有最完美的算法
二分法的应用
现在有一个列表列表中一行数字这些数字是按从小到大排列现在我需要从中快速找出我需要的值
# l1 = [11, 23, 39, 45, 59, 66, 89, 100, 165, 195, 260, 655, 745, 832, 999, 1230] # 在列表中是否能快速找到999 # 首先我们可以通过for循环查找 # check_num = 999 # for i in l1: # if i == 999: # print('找到了', i) # break # else: # print('没找到') ''' 虽然说使用for循环是可以是能够满足我们的需求的 但是for循环是从左到右一个一个提取并比对的 这样太浪费时间了 万一这个列表中的值非常多而查找的的也刚好很靠后 那么效率就会变低 ''' # 这个时候我们就能使用二分法了 ''' 二分法就是先把列表中的值提取出来进行比对如果查找的值大了就会往右查找左边的值就可以直接去除 然后在找右边列表的中间值在做对比 然后在找中间值做对比 一直找到为止 ''' l1 = [11, 23, 39, 45, 59, 66, 89, 100, 165, 195, 260, 655, 745, 832, 999, 1230] def target_num(l, check_num): if len(l) == 0: print('没有找到') return # 首先我们要提取列表的中间值 middle_index = len(l) // 2 # 首先我们需要知道列表中间的索引值 middle_num = l[middle_index] # 进行判断 if check_num > middle_num: # 提取右边的列表 right_l = l[middle_index + 1:] target_num(right_l, check_num) elif check_num < middle_num: lift_l = l[:middle_index] target_num(lift_l, check_num) else: print('找到了', check_num) target_num(l1,99) ''' 利用递归函数就能编写出二分法就可以快速找到需要查找的值 但是二分法也有一定的缺陷 如果需要查找的值是在列表的末尾或则开头效率也会变低 所以一般的算法是没有完美的 只有不断的完善,优化 '''
作业
1.编写有参函数将多种用户验证方式整合到其中
d1 = {'jason': 123}
s1 = ['kevin', 123]
def login_auth(choice):
def outer(func):
def wrapper(*args, **kwargs):
username = input('username>>:').strip()
password = input('password>>>:').strip()
password = int(password)
if choice == '列表':
if username == s1[0] and password == s1[1]:
print('登入成功')
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
elif choice == '字典':
if username in d1:
for name in d1:
if username == name and password == d1[name]:
print('登入成功')
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
else:
print('用户名不存在')
elif choice == '文件':
with open(r'a.txt', 'r', encoding='utf8')as f:
real_name, real_pwd = f.read().split('|')
if username == real_name and password == real_pwd:
print('登入成功')
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
else:
print('没有该验证方法')
return wrapper
return outer
@login_auth('列表')
def register():
print('基于列表的验证')
@login_auth('字典')
def login():
print('基于字典的验证')
@login_auth('文件')
def transfer():
print('基于文件的验证')
@login_auth('数据库')
def withdraw():
pass
register()
login()
transfer()
withdraw()
2.已知E是18求A的值
# eg: A、B、C、D、E
# 已知E是18
# 求A是多少
# 每个都大两个就是利用递归函数的特性
# age(e) = 18 # age(d) = age(e) +2 # age(c) = age(e) +2 # age(b) = age(c) +2 # age(a) = age(b) +2 def get_age(n): if n == 1: return 18 return get_age(n-1)+2 age = get_age(4) print(age)




浙公网安备 33010602011771号