推导式(列表, 集合, 字典), 生成器
1, 推导式: 通过一行循环判断,遍历出一系列数据的方式是推导式, 推导式在循环时,只能用for循环和单项判断
1.1 列表推导式: 普通推导式, 带有判断条件的推到式 , 多循环推到式, 带有判断条件的多循环推到式
list1 = [i for i in range(10)] print(list1) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 普通推导式 list2 = [i for i in range(10) if i % 2 == 0] print(list2) # [0, 2, 4, 6, 8] 带有条件的推导式 list3 = [("{}*{}={}".format(i,j,i*j)) for i in range(1,10) for j in range(1,i+1)] print(list3) # 打印99乘法表添加到列表里 多循环推导式 list4 = [(a,b) for a in range(6) for b in range(6) if a % 2 ==0 and b % 2 ==1] print(list4) # [(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)] 带有条件判断的多循环表达式 # 案例: m = [[1,2,3],[4,5,6],[7,8,9]] n = [[2,2,2],[3,3,3],[4,4,4]] # =>实现效果1 [2, 4, 6, 12, 15, 18, 28, 32, 36] # =>实现效果2 [[2, 4, 6], [12, 15, 18], [28, 32, 36]] # 效果一: list5 = [m[i][j]*n[i][j] for i in range(3) for j in range(3)] print(list5) # [2, 4, 6, 12, 15, 18, 28, 32, 36] # 效果二: list6 = [[m[i][j]*n[i][j] for i in range(3)] for j in range(3)] print(list6) # [[2, 12, 28], [4, 15, 32], [6, 18, 36]]
1.2 集合推导式,遵从列表推导式的语法,注意集合的去重和无序
# (2) 集合推导式: list1 = ["牛肉","羊肉","米饭","面条","青菜","生菜","米饭","面条"] set1 = {i for i in list1} print(set1) # 注意集合的去重性
1.3 字典推导式: 与enumerate配合使用 ,与zip配合使用
enumerate()将索引和迭代器中的值配对,组成元祖,返回迭代器,用start可以选择开始的索引号
# 方式一: list1 = ["天空","白云","大地","小草","大树"] dict1 = dict(enumerate(list1,start=1)) print(dict1) # {1: '天空', 2: '白云', 3: '大地', 4: '小草', 5: '大树'} dict1 = dict(enumerate(list1)) # 如果不设置start的话默认从索引0开始 print(dict1) # {0: '天空', 1: '白云', 2: '大地', 3: '小草', 4: '大树'} # 方式二: list1 = ["天空","白云","大地","小草","大树"] dict2 = {k:v for k,v in enumerate(list1,1)} # start可以不写 print(dict2) # {1: '天空', 2: '白云', 3: '大地', 4: '小草', 5: '大树'}
zip()将可迭代对象中的值一个个拿出来配对,组成元祖,返回迭代器,可迭代对象可以放多个,容器中不能配对的值将会被舍弃
list1 = ["天空","白云","大地","小草","大树","飞鸟"] list2 = ["蓝色","白色","褐色","绿色","翠绿"] list3 = ["无穷","造雨","生长"] it = zip(list1,list2,list3) list4 = list(it) print(list4) # [('天空', '蓝色', '无穷'), ('白云', '白色', '造雨'), ('大地', '褐色', '生长')] # 以最短的迭代对象为长度配对,其余容器中多余的就会被舍弃
list1 = ["小学","初中","高中","大学"] list2 = ["小学生","初中生","高中生","大学生"] # 方式一: dict1 = dict(zip(list1,list2)) print(dict1) # {'小学': '小学生', '初中': '初中生', '高中': '高中生', '大学': '大学生'} # 方式二: dict1 = {k:v for k,v in zip(list1,list2)} print(dict1) # {'小学': '小学生', '初中': '初中生', '高中': '高中生', '大学': '大学生'}
2. 生成器: 生成器的本质是迭代器,是一个允许自定义的迭代器
生成器的创建有两种方式:一是通过生成器表达式(外面是圆括号,里面是表达式),二是通过生成器函数(用def定义函数,函数体内含有yield关键字)
gen = (i+2 for i in range(10) if i % 2 == 0) # 生成器表达式 list1 = list(gen) print(list1)
通过生成器函数创建: 包含yield关键字的函数才是生成器函数,yield和return一样,都可以把值返回出去,但是yield在返回时,会记住上次执行的位置,下次再调用生成器的时候会从上次执行的地方往下运行
def gen_func(): print("one") yield 1 print("two") yield 2 print("three") yield 3 gen = gen_func() res = next(gen) print(res) # one # 1 res = next(gen) print(res) # two # 2 res = next(gen) print(res) # three # 3 如果第四次再调用的话,因为没有yield关键字返回数据,所以程序会报错
生成器中使用send: 生成器中使用send, send不仅可以取值,也可以发送值,
注意:第一个send不能给yield传值,默认发送None,最后一个yield接收不到send发送的值
def mygen(): print("第一个") res = yield "早上" print(res) res = yield "中午" print(res) res = yield "晚上" print("晚上没有yield了,不用吃饭了") # 打印不出来 gen = mygen() res = gen.send(None) print(res) # 第一个 # 早上 res = gen.send("早餐") print(res) # 早餐 # 中午 res = gen.send("午餐") print(res) # 午餐 # 晚上
可迭代对象中使用yield from可以将这个可迭代对象变成生成器
def func1(): list1 = range(100) yield from list1 it = func1() for i in range(3): res = next(it) print(res)
小案例: 用生成器打印斐波那契数列, 1 1 2 3 5 8 13 21 34 55 .....
# 斐波那契数列 def mygen(n): a = 0 b = 1 i = 0 while i < n: yield b a,b = b,a+b i += 1 gen = mygen(50) for i in range(10): res = next(gen) print(res)