Python-:生成器
yield¶
yield是一个很有意思的语法糖,如果在一个函数中有yield,那么这个函数就不再是一个函数了,它将返回一个生成器对象
- 生成器是通过函数实现的迭代器
- 在下次调用__next__()之后,生成器开始执行yield之后的语句
- yield 能指定生成某个函数的计算结果
- 包含yield的语句都是生成器
- 迭代器在取完所有的值之后,再次取值会报异常
Demo¶
def set_yield(lst):#定义生成器函数
for i in lst:#循环遍历参数列表
if i %3 ==0:#判断是否符合条件
yield i#根据生成器返回计算结果
a = set_yield([1,2,3,4,5,6,7,8,9,9,12,123,145,12456])
while True:
try:
print(next(a)) #通过内置函数逐一输出 因为是WhileTrue所以会无限取 会出错被下方捕捉
except:
break #捕捉异常进行输出结束
print(next(a)) #这里报错了 迭代器已经取完值了会报错 所以上方才会有异常捕捉 StopIteration
生成器推导式¶
throw:异常¶
- 迭代过程中用户手动引发异常
def l_list(lst):
try:
for i in lst:
if i % 3 == 0:
yield i
except:
raise Exception('终止了')
a = [96,19,29,72,16,3,45,6,7,9,15,10]
s = l_list(a)
print(next(s))
s.throw(Exception)
close:关闭¶
- close()用于手动关闭生成器,关闭之后无法手动再生成
def l_list(lst):
for i in lst:
if i %3 ==0:
yield i
a = [96,19,29,72,16,3,45,6,7,9,15,10]
s = l_list(a)
print(next(s))
print(next(s))
s.close() #这里进行手动关闭
print(next(a)) #这里已经关闭了 TypeError: 'list' object is not an iterator
send¶
- 不能直接用需要迭代器最少迭代一次 才能使用.因为send()是取回前一次的生成结果!
def a():
print('aaa')
p1 = yield '123'
print('bbb')
if (p1 == 'hello'):
print('p1是send传过来的')
p2= yield '234'
print(p2)
r = a()
next(r)
r.send('hello')
#print(next(r))
''' 首先 a是一个生成器 生成一个迭代器r 执行到next(r)的时候进入迭代器内部执行第一句print('aaa')语句
然后执行p1 = yield '123' 迭代跳出 执行r.send('hello')并且把'hello'传入进去赋值给p1
继续向下执行输出'bbb' 向下执行进行判断成立执行输出'p1是send传过来的',
'''
小技巧¶
- 通过yield 只能向下取值 来取出无限层的列表并生成可迭代对象(列表中的列表嵌套次数来决定递归的次数)
def list_str_yield(lst):
for i in lst:
try:
try: #如果是字符串就可以加空白字符不会出错则直接执行else语句不会进行拆分了,直接返回一整个
i+''
except: #如果不能相加会报错直接pass 执行下面的for循环进行递归
pass
else: #字符串到这里应引发一个异常 被外界捕获
raise Exception
for d in list_str_yield(i):
yield d
except:
yield i
c = [1,2,123,1,[123,4,51,[123,'abc',3,[1,7],45,51,[123,'abc',3,[1,7],45,35,],35,],51,[123,'abc',3,[1,7],45,35,],1235,123,[1234,],123]]
a = list_str_yield(c)
print(list(a))