生成器
1. 什么是生成器?
生成器的本质就是迭代器,在python社区中,大多数时候都把迭代器和生成器是做同一个概念。唯一的不同就是:迭代器都是Python给你提供的已经写好的工具或者通过数据转化得来的,比如文件句柄,iter([1,2,3])。生成器是需要我们自己用python代码构建的工具。
2. 生成器的构建方式
- 通过生成器函数
- 通过生成器推导式
1 生成器函数
在生成器中,我们可以通过yield返回数据,而不是return, return会结束程序,而yield只是生成一个对象,等待你来取。但你可以理解为return.
def fun():
print('one')
yield 11
yield 22
ret = fun()
print(ret.__next__())
当代码执行时,首先会打印one,然后将第一个yield的值交给ret(可以理解为return),此时它会保留状态,下次再取则从第一个yield之后取。如果再次执行print(ret.__next__())
则会取到第二个yield之后 的值,即 22。
总结:yield与return的区别: return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。 yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素
send
send用来向生成器中传值,它本身包含next方法,看下面的例子:
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield
print(f'{name} start to eat {food}')
dog = gen('alex')
next(dog)
# 还可以给上一个yield发送值
dog.send('骨头')
dog.send('狗粮')
dog.send('香肠')
"""
alex ready to eat
alex start to eat 骨头
alex start to eat 狗粮
alex start to eat 香肠
"""
首先,next会将程序执行到yield,但上面next并不会打印出什么,(把yield理解为return,即即程序执行到yield返回了,没有赋值,但保留了状态,等待下一次从赋值开始)。随后的send将值传入,而程序从上次的状态接着执行,即赋值操作:foo='骨头', 所以我们看到的是:"alex start to eat 骨头"
send() vs next() 我们看下官方文档:
generator.send(value) 恢复执行并向生成器函数“发送”一个值。value 参数将成为当前 yield 表达式的结果。 send() 方法会返回生成器所产生的下一个值,或者如果生成器没有产生下一个值就退出则会引发 StopIteration。
当调用 send() 来启动生成器时,它必须以 None 作为调用参数,因为这时没有可以接收值的 yield 表达式。
相同: 1. 生成器对应的yield向下执行一次 2. 获取yield生成的值
不同: 1. 第一次取yield的值时只能用next,如果非要用send,必须要send(none) #因为没有yield语句来接收这个值
yield from
当使用 yield from
def fun():
yield ['a', 'b', 'c']
f = fun()
print(f.__next__())
这种情况下,会直接返回整个列表,但如果使用yield from
就会返回列表中单个元素。
2 推导式
gen = (i**2 for i in range(10))