昨日内容回顾
装饰器:在不改变被装饰原有的调用方式和内部代码的情况下增加新的功能
多层装饰器:
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
@outer1
@outer2
@outer3
def index():
pass
'''
出现多层语法糖的时候,执行是从下到上的,靠近函数名的先开始执行
'''
有参装饰器:
如果在外层函数里传入参数是不能的,那里只能传入函数名,传入参数以后语法糖不能执行了
如果在内层函数里传入参数的话也是不能的,改变了装饰器的原有条件
解决方法:在最外面加一层函数,可以传入多个值,返回值设置为下一层的函数名,然后就是正常的装饰器
def outer(condition,type_user):
def login_auth(func_name): # 这里不能再填写其他形参
def inner(*args, **kwargs): # 这里不能再填写非被装饰对象所需的参数
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 应该根据用户的需求情况执行不同的代码
if type_user =='jason':print('VIP')
if condition == '列表':
print('使用列表作为数据来源')
elif condition == '字典':
print('使用字典作为数据来源')
elif condition == '文件':
print('使用文件作为数据来源')
else:
print('目前只有上面几种方式')
return inner
return login_auth
@outer('文件','jason') # 函数名加括号执行优先级 @login_auth
def index():
print('from index')
index()
递归方法:
一层比一层简单,要有结束条件
递归:一层层向下找答案
回溯:根据已知条件去推结果
算法--二分法:
算法:解决问题的方法
对半平分与目标数字进行比较,目标数字大的话就在后半截,目标数字小的话就在前半截,然后再进行对半分比较大小
缺点是如果目标函数在首部或者尾部的时候采用二分法找的话效率会低,它必须是有序数列
今日内容学习
三元表达式
特点:可以减少代码的行数
语法结构:
值1 if 条件 else 值2
可以理解为:
条件为真时的结果 if 条件 else 条件为假时的结果
限制:仅限于二选一的情况并且不建议嵌套使用
例题展示:
# 比较俩个数的大小
num1 = input('num1:')
num2 = input('num2:')
if num1 > num2:
return num1
else:
return num2
# 函数编写俩个数的大小
def num_max(num1, num2):
if num1 > num2:
return num1
else:
return num2
res = num_max(12, 13)
print(res) # 13
# 采用三元表达式
def num_max(num1, num2):
return num1 if num1 > num2 else num2
res = num_max(12, 13)
print(res) # 13
print('haha' if 0 else 'heihei')
print('huhu' if 1 else 'gaga')
'''
heihei
huhu
'''
# 三元表达式不只是能用在数字之间
各种生成式
1.列表生成式
# 给列表中的所有数据值都加上_nb
l1 = ['aa', 'bb', 'cc', 'dd', 'ee']
# # 根据已学知识我们可以用for循环来实现
# # 1.先定义一个新的列表
new_list = []
# # 2.循环原列表中所有的数据值,使用for循环
for name in l1:
# # 3.name是每次循环取出来的名字,给每个名字拼接后缀
new_name = name + '_nb'
# # 4.拼接好的使用列表的内置方法append,追加到空的列表中
new_list.append(new_name)
print(new_list) # ['aa_nb', 'bb_nb', 'cc_nb', 'dd_nb', 'ee_nb']
# 使用列表生成式
l1 = ['aa', 'bb', 'cc', 'dd', 'ee']
new_list = [name + '_nb' for name in l1]
print(new_list) # ['aa_nb', 'bb_nb', 'cc_nb', 'dd_nb', 'ee_nb']
# 列表生成式支持if判断(列表生成式中只能出现for、if)
l1 = ['aa', 'bb', 'cc', 'dd', 'ee']
new_list = [name + '_nb' for name in l1 if name != 'aa']
'''
1.首先执行的是for循环
2.for循环取出来的数据值进入if的判断,如果条件成立就会执行前面拼接的操作,如果不成立就直接弃掉这个数据值
3.判断完之后进行name + '_nb'的操作
4.然后默认放入这个列表中
'''
2.字典生成式
# 字典生成式
d1 = ['aa', 'bb', 'cc', 'dd', 'ee']
new_dict = {i:'jason' for i in range(5)}
print(new_dict) # {0: 'jason', 1: 'jason', 2: 'jason', 3: 'jason', 4: 'jason'}
'''
1.首先执行for循环
2.查看后面有没有if条件,如果有的话执行if条件,如果没有的话就看前面的执行语句
3.然后将i的值依次放入前面的语句中
4.因为整个外面使用{}包裹,所以就直接以字典的方式输出一对对键值对
'''
# 字典生成式加if语句
d1 = ['aa', 'bb', 'cc', 'dd', 'ee']
new_dict = {i:'jason' for i in range(5) if i == 4}
print(new_dict) # {4: 'jason'}
'''
打印结果就是一个键值对,根据if条件进行打印
'''
3.集合生成式
#集合生成式
new_set = {i for i in range(10)}
print(new_set) # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
new_set = {i for i in range(10) if i == 6}
print(new_set) # {6}
'''
1.同样也是先执行for循环,如果后面没有if语句就之前前面的语句
2.将循环出来的数据值挨个放到前面的语句中,然后输出
3.外面是{}包裹着直接输出的就是集合
'''
注意:元组没有生成式
匿名函数
1.可以理解为没有函数名的函数
2.关键字:lambda
3.表达式:lambda 参数:return 返回值
匿名函数可以看作是一个表达式,只是它必须要有返回值而已
4.优点:可以省去定义函数的过程,结合一些内置函数使用
可以变为有名函数
减少代码,是代码更加简洁
5.应用案例(max,min,sorted,map,reduce,filter)
匿名集合内置函数使用
# 常见内置函数
# 1.max()----求最大值
l1 = [1, 2, 3, 4, 6, 8, 10, 35, 67, 34, 76, 90, 15, 38, 29]
res = max(l1)
# 如果是在字典中去v值的最大值呢??
d1 = {'zz': 199, 'ss': 67, 'dd': 3456, 'xx': 12345}
res = max(d1, key=lambda k: d1.get(k))
print(res) # xx
'''
1.max底层是for循环
2.如果没有后面的key值,拿到的是k键,然后就是直接进行比较,通常的话是字符串,然后字符串比较通常是那第一位,通过编码进行比较大小的
3.如果有key值,for循环拿到的是k值,然后k值作为参数传给lambda中的参数,然后返回值通过get方法去得到v值,此时返回值就是v值,然后拿着v值进行比较
4.最后输出的是名字,是因为原来for循环出来的是k值,最终结果还是按照for循环来的
'''
# 如果匿名函数不可以用,那就使用函数
def index(k):
return d1.get(k)
res = max(d1,key=index)
print(res) # xx
'''需要注意的是index只能有一个形参,因为max底层是一个for循环一次只能拿一个值'''
# # 2.min()----求最小值
res1 = min(l1) # 1
print(res1) # 90
重要内置函数
# 1.map()----映射
l1 = [1, 2, 3, 4, 6, 8, 10, 35, 67, 34, 76, 90, 15, 38, 29]
res = map(lambda x: x + 20, l1)
print(list(res)) # [21, 22, 23, 24, 26, 28, 30, 55, 87, 54, 96, 110, 35, 58, 49]
'''
1.底层用的是for循环,
2.挨个将列表中的值取出来
3.每次取出来的函数交给函数的形参
4.然后传给返回值得出结果
'''
# 自定义函数
def index(a):
return a + 20
res = map(index, l1)
print(list(res))
# 2.filter()----过滤掉不符合条件的元素,返回符合条件的元素
l1 = [1, 2, 3, 4, 6, 8, 10, 29]
res = filter(lambda a: a != 3, l1)
print(list(res)) # [1, 2, 4, 6, 8, 10, 29]
# 自定义函数
def index(a):
return a != 3
res = filter(index,l1)
print(list(res)) # [1, 2, 4, 6, 8, 10, 29]
# 3.reduce()---它与map()不同的是它需要传入俩个值
from functools import reduce
l2 = [1,4,5,7]
res_l2 = reduce(lambda x, y: x + y,l2,100)
print(res_l2) # 17
'''
1.将很多单体变成一个整体,
2.一次性要给予俩个参数,第一次取值是需要俩个值,之后就是取一个了,其中另一个是上一次的返回值
3.后面还可以传值进去,就是在列表里的执行完后面又加上这个值
'''
# 4.zip()
n1 = [1,2,3]
n2 = ['jason','kevin','oscar']
res = zip(n1,n2)
print(list(res)) # [(1, 'jason'), (2, 'kevin'), (3, 'oscar')]
'''
1.可以拼接多个值
2.拼接的值要支持for循环
3.如果存放的数据长短不一,那就按照最短的那个来连接
'''
作业
每个人将多层装饰器及有参装饰器的执行流程用文字具体描述出来
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
@outter2
@outter3
def index():
print('from index')
index()
'''
1.出现多个语法糖的时候,先看离函数最近的语法糖,语法糖直到最后一个的时候才将与正真函数一样的函数名的名字拿去赋值,否则就要看它的返回值将返回值看作是赋值的名字
2.语法糖的功能是将紧挨着的函数名当作参数传给@后面的函数
2.1 outter3(index)(函数名加括号执行优先级最高,它最先开始执行,然后执行了 【print('加载了outter3')】,再执行函数wrapper3,再执行return wrapper3)-->wrapper3 =outter3(index)
2.2 wrapper3是一个函数名紧接着触发了@outter2,然后跟上面操作一样,(函数名加括号执行优先级最高,它最先开始执行,然后执行了 【print('加载了outter2')】,再执行函数wrapper2,再执行return wrapper2)-->wrapper2 =outter2(wrapper3)
2.3 wrapper2触发了@outter1,.......-->index =outter1(wrapper2)
3.调用index()的执行流程,此时index是wrapper1,那现在其实就是wrapper1(),
wrapper1函数开始执行-->【 print('执行了wrapper1')】,res1 = func1(*args, **kwargs),func1此时是wrapper2,return res1就到了wrapper2
wrapper2函数开始执行-->【 print('执行了wrapper2')】,res2 = func2(*args, **kwargs),func2此时是wrapper3,return res2就到了wrapper3
wrapper3函数开始执行-->【 print('执行了wrapper3')】,res3 = func3(*args, **kwargs),func3此时是index,return res3就到了print('from index')
4.总结执行流程:
多层装饰器的时候从最下面开始向上执行先执行语法糖根据语法糖与函数名的触发条件,将外层的函数从上至下一个一个的执行到最后回归到最开始的真正的函数名(并非真正的函数名是跟真正的函数名名字一样)的时候,再开始用上至下执行内部的函数,最终回归到要执行的那个函数,打印输出结果。
'''
2.有参装饰器
def outer(condition,type_user):
def login_auth(func_name): # 这里不能再填写其他形参
def inner(*args, **kwargs): # 这里不能再填写非被装饰对象所需的参数
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 应该根据用户的需求情况执行不同的代码
if type_user =='jason':print('VIP')
if condition == '列表':
print('使用列表作为数据来源')
elif condition == '字典':
print('使用字典作为数据来源')
elif condition == '文件':
print('使用文件作为数据来源')
else:
print('目前只有上面几种方式')
return inner
return login_auth
@outer('文件','jason') # 函数名加括号执行优先级 @login_auth
def index():
print('from index')
index()
'''
执行总结:
1.在外部函数里加入形参,那么就得在语法糖里加入参数,但是如果在语法糖里加入了参数,那解释器自动识别函数名加()执行优先级,那么语法糖就不会执行了,外部函数括号里只能用来接收被装饰的函数名
2.在内部函数里加入形参,那么在执行内部函数的时候就得必须传入一个参数,但是传入了参数就不符合装饰器的原则了原本函数执行的时候是不需要传入参数的,可是现在需要,因此这种方法也不能
3.所以只能使用闭包函数解决,在最外面套一个函数,将需要传入的参数设置为形参,返回值为原外层函数,然后这个时候里面就是一个完整的装饰器,没有破坏它,同时这个额外新增的函数是可以传入多个值的
'''