python学习Day18
Day 18
今日内容概要
- 多层装饰器
- 有参装饰器
- 递归函数
- 算法(二分法)
- 函数相关偷懒操作
今日内容详细
1.多层装饰器
def outter1(func1): # func1=wrapper2函数名
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2): #func2=wrapper3函数名
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3): #func3=真正的index函数
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1 # index=outter1(wrapper2) index现在就是wrapper1
@outter2 # wrapper2=outter2(wrapper3)
@outter3 # wrapper3=outter3(真正的index函数名)
def index():
print('from index')
1.一个函数上面加了三个语法糖装饰器,是怎么执行的?
加载了123 执行了321 from index
2.执行后上面7个print先后打印顺序是什么?
'''
语法糖的功能:
会自动将下面紧挨着的函数名当作参数传递给@符号后面的函数名(加括号调用)
涉及到多个语法糖装饰一个函数名:
语法糖从下往上执行 只有最后一个会重命名操作
'''
2.有参装饰器
def login_auth(func_name):
def inner(*args, **kwargs):
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if username == 'jason' and password == '123':
res = func_name(*args, **kwargs)
return res
else:
print('用户权限不够 无法调用函数')
return inner
"""
需求:在装饰器内部可以切换多种数据来源
列表
字典
文件
"""
#当编写的装饰器需要外界传入额外的数据来控制代码的分支,则需要在装饰器外部再套一层,然后在调用的时候在语法糖后面跟括号添加要传入的数据
def outer(condition,type):#把需要的额外数据放在这里
def login_auth(func_name): #这个地方不能放condition 只能接收被装饰的函数名 不能再填写其他形参
def inner(*args, **kwargs): #这个地方也不能放condition 加了会改变原函数的调用方式
username = input('username>>>:').strip()
password = input('password>>>:').strip()
#根据用户需求执行不同代码
if type == 'jason':print('VIP')
if condition == '列表':
print('使用列表来对比用户数据')
elif condition == '字典':
print('使用字典来对比用户数据')
elif condition == '文件':
print('使用文件来对比用户数据')
else:
print('没有该功能')
return inner
return login_auth
@outer('列表','jason')
def index():
print('from index')
index()
#这样做的目的仅仅是为了给装饰器代码传递更多额外的数据
3.递归函数
'''
递归函数:
函数直接或间接调用了自己就叫递归调用
'''
1.递归直接调用:(自己调自己)
def index():#1.定义一个函数index()
print('from index')#3.执行函数体内部代码
index()#4.直接调用index() 此时的顺序就是123434343434一直重复 这就是函数递归调用
index()#2.调用index()函数
2.递归间接调用:(我调别人别人调我)
def index():#1.把函数名称放在全局空间中
print('from index')#6.#10.
func()#7.#11
def func():#2.把函数名称放在全局空间中
print('from func')#4.#8.
index()#5.#9.
func()#3.调用函数func() 456789就会一直重复
——————————————————————————————————————————————————————————————————
'python中官方允许函数中最大调用的次数限制是1000 但是用代码验证可能会是996、997..'
1)计数器验证递归最大次数:
count = 1
def index():
print('from index')#
global count #局部名称空间改全局需要加global关键字
print(count)
count +=1
index()
index()#996次
2)模块获取官方递归最大次数
import sys
print(sys.getrecursionlimit())#1000
#模块修改递归次数
import sys
sys.setrecursionlimit(2000)#把递归次数定义为2000
print(sys.getrecursionlimit())
递归函数的应用场景:
递推:一层一层往下寻找答案
回溯:根据已知条件得出最终结果
写递归函数需注意:
1.每次调用的时候都必须'比上一次简单'
2.递归函数最终都必须要有一个明确的'结束条件'
例如:问A名字,A说我比B大两岁,B说我比C大1岁,C说我18岁。
这个过程就是调用的过程,C就是明确的结束条件
递归函数练习:
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, ]]]]]]]]]]
# 循环打印出列表中所有的数字
# 1.for循环l1里面所有的数据值
# 2.判断当前数据值是否是数字 如果是则打印
# 3.如果不是则继续for循环里面所有数据值
# 4.判断当前数据值是否是数字 如果是则打印
# 5.如果不是则继续for循环里面所有数据值
# 6.判断当前数据值是否是数字 如果是则打印
错误示范:
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, ]]]]]]]]]]
for i in l1:
if isinstance(i,int):#判断某个数据类型是不是属于另外数据类型 判断i是否属于整型
print(i)#如果是则打印i
else:
for j in i:#如果不是整型则继续让j去循环取值
if isinstance(j,int):
print(j)
'这样做会一直重复上述操作 如果有1000个数据值则要重复1000次 所以我们要用递归函数'
————————————————————————————————————————————————————————————————————————————
正确示范:
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, ]]]]]]]]]]#1.
def num(l1):#2.
for i in l1:#4.让i循环打印l1
# print(i)#1和[2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]
if isinstance(i, int):#判断某个数据类型是不是属于另外数据类型 判断i是否属于整型
print(i)#如果是则打印i
else:
num(i)#如果不是整型则把后面的列表传给函数继续重复第4步
num(l1)#3.
4.算法(二分法)
1.什么是算法?
算法就是解决问题的方法(比如物品坏了,我有几种方法去解决)
'''
算法永远都在精进,很少有最完美的算法
小公司一般没有算法工程师,只有大厂才有,薪资也很高
很多面试官都喜欢问算法相关问题
算法分为:二分法、快拍、插入、堆排、链表、双向链表、约瑟夫问题
'''
算法——二分法:
算法中最简单的算法,就是把数据拆成两半去判断,然后再拆成两半去判断,直到找到需要的数据,类似于递归函数
eg:用算法判断999在不在以下列表中,如果在就取出该值
l1 = [11, 23, 32, 45, 65, 78, 90, 123, 432, 467, 567, 687, 765, 876, 999, 1131, 1232]
————————————————————————————————————————————————————————————————————————————————
方法一:用for循环
缺陷:如果列表中数据特别多 需要的数据在最后几个 那代码执行的时间就会做多余的浪费
————————————————————————————————————————————————————————————————————————————————
方法二:二分法来做
缺陷:1.数据必须是有顺序的,不能打乱顺序
2.查找的数字如果在开头或者结尾,效率可能会很低
l1 = [11, 23, 32, 45, 65, 78, 90, 123, 432, 467, 567, 687, 765, 876, 999, 1131, 1232]
#5.根据第三第四步判断需要用递归函数来操纵
def num(l1,number):#l1一会要当作参数传进来 number也当作参数放进去用于以后用户随意修改要查的数据
#8.添加递归函数的结束条件
if len(l1)==0:
print('找不到')
return
#1.先获取数据列表中中间的数
middle=len(l1)//2#统计出列表中有多少数据再整除得到中间数的索引值
value=l1[middle]#把列表中中间的值赋值给value
#2.判断中间的数据值与目标数据值谁大谁小
if number > value:
#3.说明查找的数据在列表大的那一边
right_l1 = l1[middle+1:]#利用列表的切片取值取当前位置一直到后面所有,因为当前位置肯定比999小所以让索引加1
#3.1获取右边中间的值
#3.2与目标数据值对比
#3.3根据大小切割数据集
#6.添加递归函数代码
print(right_l1)
num(right_l1,number)#把右边的列表当作新列表传给参数,再把要对比的数据传给参数
elif number < value:
#4.说明查找的数据在列表小的那一边
left_l1 = l1[0:middle]#利用列表索引取值取从0开始一直到当前位置前(顾头不顾尾)所有值
# 4.1获取左边中间的值
# 4.2与目标数据值对比
# 4.3根据大小切割数据集
#7.添加递归函数代码
print(left_l1)
num(left_l1,number)
else:
print('该位置就是目标数据所在位置',number)
num(l1,999)
作业:
1.尝试编写有参函数将多种用户验证方式整合到其中
直接获取用户数据比对
数据来源于列表
数据来源于文件
2.尝试编写递归函数
推导指定某个人的正确年龄
eg: A B C D E 已知E是18 求A是多少
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)