【2022-07-06】python多层装饰器与递归函数
Python装饰器及递归函数
多层装饰器
触发条件
"""
语法糖的功能:会自动将下面紧挨着的函数名当做参数传递给@符号后面的函数名(加括号调用)
涉及到多个语法糖装饰一个函数名,从下往上执行,最后一个语法糖才会做重命名操作
"""
先看三个语法糖的执行顺序,再看print语句的打印顺序,最后看调用index函数的执行流程
def outer1(function1): # function1 = wrapper2函数名
print('加载了outer1') # 第三个打印的语句
def wrapper1(*args, **kwargs):
print('执行了wrapper1') # 第四个打印的语句
res1 = function1(*args, **kwargs)
return res1
return wrapper1
def outer2(function2): # function2 = wrapper3函数名
print('加载了outer2') # 第二个打印的语句
def wrapper2(*args, **kwargs):
print('执行了wrapper2') # 第五个打印的语句
res2 = function2(*args, **kwargs)
return res2
return wrapper2
def outer3(function3): # function3 = 真正的index函数
print('加载了outer3') # 第一个打印的语句
def wrapper3(*args, **kwargs):
print('执行了wrapper3') # 第六个打印的语句
res3 = function3(*args, **kwargs)
return res3
return wrapper3
@outer1 # index = outer1(wrapper2) # index为wrapper1 调用outer1把wrapper2函数名当做参数传进去
@outer2 # wrapper2 = outer2(wrapper3) # 调用outer2把wrapper3函数名当做参数传进去
@outer3 # wrapper3 = outer3(真实的index函数名)
def index():
print('hello word') # 最后一个打印的语句
index()
执行index后的打印结果:
加载了outer3
加载了outer2
加载了outer1
执行了wrapper1
执行了wrapper2
执行了wrapper3
hello word
有参装饰器
当我们在编写一个装饰器的时候,这个装饰器内部需要外界传入额外的数据来控制代码的分支,这个时候就需要给原来的装饰器模板再套一层,,然后在使用的时候,在加语法糖的时候,给它直接添加额外的数据,这个时候的装饰器就和普通的装饰器一样了,这就是有参装饰器
# 需求:在使用装饰器进行用户校验时,我可以随意切换数据的来源,无论是字典、列表还是文件
# 1.先定义一个outer函数
def outer(condition): # 4.字典传给了condition
def login_auth(function_name): # 5.执行login_auth函数 无法添加更多的形参,只能接收一个被装饰对象的函数名
def inner(*args, **kwargs): # 无法添加参数,因为它是专门用来给被装饰器对象传参的
username = input('please your username>>>:').strip()
password = input('please your password>>>:').strip()
# 根据用户需求执行不同的代码
if condition == '字典':
print('使用字典作为用户数据来源,进行比对')
elif condition == '列表':
print('使用列表作为用户数据来源,进行比对')
elif condition == '文件':
print('使用文件作为用户数据来源,进行比对')
else:
print('其他操作情况')
return inner
return login_auth # 6.返回login_auth
@outer('字典') # 3.先看outer函数(),执行outer函数
def index(): # 2.定义一个index函数
print('hello word')
index()
递归函数简介
递归函数是一个直接或间接调用函数本身的嵌套型函数,每一个递归函数都有递推(递的概念)和回推(归的概念)的过程。递推过程是将一个复杂的大问题一步步分解成简单的过程类似的小问题,而回推过程是在递归历史的基础上,从最后的最简单的小问题开始,结合该层上一层的输入参数与输出结果,按逻辑一步步向上恢复成最初的复杂的大问题。
# 递归函数的概念 在编程语言中,函数直接或者间接调用了函数本身,则该函数称之为递归函数
# 递归调用:直接调用
# def index(): # 1.先定义一个函数index
# print('hello word') # 3.打印hello word
# index() # 4.这又是一个index函数调用,它反复执行调用自己,最后的结果就是报错
# index() # 2.调用index函数
# 递归调用:间接调用
# def index(): # 1.定义一个函数index
# print('hello word') # 6.打印hello word
# home() # 7.再次调用home函数,打印from home 依次类推,无限重复
#
#
# def home(): # 2.定义一个函数home
# print('from home') # 4.打印from home
# index() # 5.调用index函数
#
#
# home() # 3.调用home()函数
# Python中允许函数最大递归调用的次数为:1000 官方给出的限制是1000 用代码去验证可能会有些许偏差(996 995...)
# count = 0
# def index():
# print('hello word')
# global count
# print(count)
# count += 1 # count = count + 1
# index()
# index()
# import sys
# print(sys.getrecursionlimit()) # 1000 获取递归最大次数
# sys.setrecursionlimit(2000) # 自定义最大次数
# print(sys.getrecursionlimit()
# def index():
# print('hello word')
# global count
# print(count)
# count += 1 # count = count + 1
# index()
# index()
# import sys
# print(sys.getrecursionlimit()) # 1000 获取递归最大次数
# sys.setrecursionlimit(2000) # 自定义最大次数
# print(sys.getrecursionlimit())
递归函数的使用
"""
递归函数真正的应用场景
递推:一层层往下寻找答案
回溯:根据已知条件推导最终结果
递归函数
1.每次调用的时候都必须要比上一次简单!!!
2.并且递归函数最终都必须要有一个明确的结束条件!!!
"""
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, ]]]]]]]]]]
# 循环打印出列表中所有的数字
# 1.for循环l1里面所有的数据值
# 2.判断当前数据值是否是数字 如果是则打印
# 3.如果不是则继续for循环里面所有数据值
# 4.判断当前数据值是否是数字 如果是则打印
# 5.如果不是则继续for循环里面所有数据值
# 6.判断当前数据值是否是数字 如果是则打印
def get_num(l1):
for i in l1:
if isinstance(i,int):
print(i)
else:
get_num(i)
get_num(l1)
算法之二分法
什么是算法
算法就是解决问题的方法
算法永远都在精进 但是很少有最完美的算法
算法很多时候可能没什么用
小公司一般不会有算法工程师 只有大公司才会有
算法工程师待遇很高 但是产出很少 甚至几年几十年都没有成果
有点相当于科研人员
很多大型互联网面试都喜欢问算法
平时学有余力可以简单看看(临时抱佛脚)
二分法 快拍 插入 堆排 链表 双向链表 约瑟夫问题
二分法
是所有算法里面最简单的算法
也有人说二分法不是算法
l1 = [11, 23, 32, 45, 65, 78, 90, 123, 432, 467, 567, 687, 765, 876, 999, 1131, 1232]
def get_num(l1, target_num):
# 添加递归函数的结束条件
if len(l1) == 0:
print('不好意思 找不到')
return
# 1.先获取数据集中间那个数
middle_index = len(l1) // 2
middle_value = l1[middle_index]
# 2.判断中间的数据值与目标数据值孰大孰小
if target_num > middle_value:
# 3.说明要查找的数在数据集右半边 如何截取右半边
right_l1 = l1[middle_index + 1:]
# 3.1.获取右半边中间那个数
# 3.2.与目标数据值对比
# 3.3.根据大小切割数据集
# 经过分析得知 应该使用递归函数
print(right_l1)
get_num(right_l1, target_num)
elif target_num < middle_value:
# 4.说明要查找的数在数据集左半边 如何截取左半边
left_l1 = l1[:middle_index]
# 4.1.获取左半边中间那个数
# 4.2.与目标数据值对比
# 4.3.根据大小切割数据集
# 经过分析得知 应该使用递归函数
print(left_l1)
get_num(left_l1, target_num)
else:
print('找到了', target_num)
# get_num(l1, 999)
get_num(l1, 1000)
"""
二分法缺陷
1.数据集必须是有序的
2.查找的数如果在开头或者结尾 那么二分法效率更低!!!
"""
课题演练
# 1.有参装饰器多种用户认证方式
data_list = ['jason|123', 'kevin|321', 'oscar|222']
def login_auth(condition):
def outer(func_name):
def inner(*args, **kwargs):
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if condition == 'absolute':
if username == 'jason' and password == '123':
res = func_name(*args, **kwargs)
return res
else:
print('你不是jason 不允许执行')
elif condition == 'list_type':
for user_data in data_list: # 'jason|123'
real_name, real_pwd = user_data.split('|')
if real_name == username and real_pwd == password:
res = func_name(*args, **kwargs)
return res
elif condition == 'file_type':
with open(r'userinfo.txt','r',encoding='utf8') as f:
for line in f:
real_name, real_pwd_n = line.split('|')
if real_name == username and password == real_pwd_n.strip('\n'):
res = func_name(*args, **kwargs)
return res
return inner
return outer
@login_auth('absolute')
def func1():
print('from func1')
return 1
@login_auth('list_type')
def func2():
print('from func2')
return 2
@login_auth('file_type')
def func3():
print('from func3')
return 3
func1()
func2()
func3()
# 2.递推回溯求解某个人的年龄
def get_age(n):
if n == 1:
return 18
return get_age(n-1) + 2
res = get_age(5)
print(res)

浙公网安备 33010602011771号