15. Python之yield表达式和生成式
2021-02-01 本文已影响0人
随便写写咯
1 yield表达式的应用
1.1 利用yield返回值给函数体的变量传值
def func(name):
print('%s 准备点菜' %(name))
while True:
dish = yield None
print('%s 点了 %s' %(name, dish))
g=func('第一桌')
first_dish = next(g)
print(first_dish)
第一桌 准备点菜
None # 利用yield传值, 需要指定yield的返回值
def func(name):
print('%s 准备点菜' %(name))
while True:
dish = yield '鲍鱼'
print('%s 点了 %s' %(name, dish))
g=func('第一桌')
first_dish = next(g)
print(first_dish)
第一桌 准备点菜
鲍鱼
1.2 yield表达式格式生成器
g.send() 给yield赋值, yield会将值转给变量, 此时变量拿到的是yield从g.send()接收到的值
g.send() 相当于执行了next方法, 只不过具备了传值功能, 如果单纯的执行next方法, 那么给变量传的就是yield的返回值
def func(name):
print('%s 准备点菜' %(name))
while True:
dish = yield
print('%s 点了 %s' %(name, dish))
g=func('第一桌')
g.send(None) # 第一次执行g.send需要传None来初始化生成器, 让函数先挂起在yield,等待send传值
g.send('土豆') # 之后每一次变量dish的值, 取决于通过g.send()给yield传的值, 每执行一次send, 会把值传给变量, 然后打印print, 之后再回到yield, 等着下一次send传值
g.send('地瓜') # 第二次传了土豆, 那么yield就会把土豆传给dish, 之后在打印print
第一桌 准备点菜
第一桌 点了 土豆
第一桌 点了 地瓜
通过g.close()结束传值
def func(name):
print('%s 准备点菜' %(name))
while True:
dish = yield
print('%s 点了 %s' %(name, dish))
g=func('第一桌')
g.send(None)
g.send('土豆')
g.send('地瓜')
g.close()
g.send('肉')
g.send('肉')
StopIteration
第一桌 准备点菜
第一桌 点了 土豆
第一桌 点了 地瓜
g.send()方法, 一次只能传一个值, 但是可以传容器类型
1.3 表达式综合应用
def func(name):
print('%s 准备点菜' %(name))
while True:
dish = yield 111
print('%s 点了 %s' %(name, dish))
g=func('第一桌') # 运行函数, 拿到生成器
res1 = g.send(None) # 首次执行, 需要通过send(None)来初始化生成器, 让函数挂起在yield,等待传值, 之后每次通过send给yield传值, 进而给变量dish传值, 每次传值yield的返回值就是yield后的值
print(res1)
res2 = g.send('土豆')
print(res2)
res3 = g.send('地瓜')
print(res3)
第一桌 准备点菜
111
第一桌 点了 土豆
111
第一桌 点了 地瓜
111
执行顺序
1. 执行send方法,将参数传给yield, 进而传给dish变量
2. 执行print, 函数代码结束, 返回while循环, 然后将yield后的值返回
3. yield的返回值就看yield后跟了什么, yield拿到返回值后, 程序挂起在yield, 等待下一次send传值
yield返回值是列表的情况
def func(name):
print('%s 准备点菜' %(name))
food_list = []
while True:
dish = yield food_list
print('%s 点了 %s' %(name, dish))
food_list.append(dish)
g=func('第一桌')
- 第一步, 执行send(None), 初始化生成器, yield返回空列表,程序挂起在yield等待send传值
res1 = g.send(None)
print(res1) # g.send()的返回值就是yield后的值
第一桌 准备点菜
[]
- 第二次, send传值'土豆'
1. yield从send拿到土豆, 然后传给dish, 接着执行print代码
2. print代码执行完, 执行列表追加, 将土豆追加到列表, 此时代码执行完, 返回循环, 进入yield
3. yield拿到返回值food_list列表, 因此打印res2, 会拿到yield的新的返回值也就是追加后的列表
4. 程序挂起在yield, 等待下次send传值
def func(name):
print('%s 准备点菜' %(name))
food_list = []
while True:
dish = yield food_list
print('%s 点了 %s' %(name, dish))
food_list.append(dish)
g=func('第一桌')
res1 = g.send(None)
print(res1)
res2 = g.send('土豆') #
print(res2)
- 第三次, send传值'地瓜'
def func(name):
print('%s 准备点菜' %(name))
food_list = []
while True:
dish = yield food_list
print('%s 点了 %s' %(name, dish))
food_list.append(dish)
g=func('第一桌')
res1 = g.send(None)
print(res1)
res2 = g.send('土豆')
print(res2)
res3 = g.send('地瓜')
print(res3)
第一桌 准备点菜
[]
第一桌 点了 土豆
['土豆']
第一桌 点了 地瓜
['土豆', '地瓜']
2 三元表达式
可以简化利用条件判断拿到返回值的需求
格式:
条件成立的返回值 if 条件判断 else 条件不成立的返回值
正常情况根据条件拿到返回值
def max2(x,y):
if x > y:
return x
else:
return y
res = max2(1,2)
print(res)
2
利用三元表达式
x = 1
y = 2
res = 111 if x > y else 222
print(res)
222
函数内使用三元表达式
def max2(x,y):
res = 111 if x > y else 222
print(res)
max2(1,2)
2
3 列表生成式
用精简的代码生成新的列表
举例: 将名字中以soccer结尾的元素提取到新的列表
play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
soccer_play = []
for name in play:
if name.endswith('soccer'):
soccer_play.append(name)
print(soccer_play)
['david_soccer', 'owen_soccer', 'cluo_soccer']
利用列表生成式
play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
soccer_play = [name for name in play if name.endswith('soccer')]
print(soccer_play)
列表生成式格式
新列表 = [如果条件成立就追加到列表的值 for 循环 if 条件判断]
新列表 = [如果条件成立就追加到列表的值 for 循环] # 可以不接if条件, 那默认就是条件永远为True
新列表 = [任何值 for 循环] # 追加的值可以是任意值
案例: 把列表中所有小写字母, 变成大写字母
play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
new_play = [name.upper() for name in play]
print(new_play)
['DAVID_SOCCER', 'OWEN_SOCCER', 'CLUO_SOCCER', 'MICHAEL_BASKETBALL']
案例: 把列表中所有名字去掉_soccer后缀
play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
new_play = [name.replace('_soccer','') for name in play]
print(new_play)
['david', 'owen', 'cluo', 'michael_basketball']
4 字典生成式
案例1:
keys = ['name','age','job']
dict = {key:None for key in keys}
print(dict)
{'name': None, 'age': None, 'job': None}
案例2:
items = [('name','admin'),('age','20'),('gender','male')]
dict = {k:v for k,v in items if k != 'gender'} # 利用元组的解压赋值, 判断k是否不等于gender, 如果成立就加入到字典
print(dict)
5 集合生成式
案例:
keys = ['name','age','gender']
set = {key for key in keys}
print(set)
6 生成器表达式
综合案例: 统计一个文本中的字符总个数
方法1: 代码过长
with open(r'user_info.txt', mode = 'rt', encoding='utf-8') as f:
sum = 0 # 初始化总个数为0
for i in f: # for循环一个文件, 每次取出文件的一行, 并且是字符
sum += len(i) # len(i)计算出每行的字符个数, 追加给sum
print(sum)
方法2: 虽然代码精简, 但是一旦文件行数过多的情况下, 每次统计出来一行的字符个数, 再追加到列表, 会造成列表元素过多, 占用内存过大
with open(r'user_info.txt', mode = 'rt', encoding='utf-8') as f:
list = [len(i) for i in f ]
print(sum(list))
方法3: 利用生成器表达式, 效率最高
with open(r'user_info.txt', mode = 'rt', encoding='utf-8') as f:
res = sum((len(line) for line in f))
print(res)