在程序中除了迭代器还有生成器均是可迭代对象,迭代器是通过移动游标来遍历数据,那生成器呢
生成器
生成器创建方式(python)
- (表达式)
1
2
3
4
5
6generator = (i for i in [1, 2, 3]) // 这里有区别于 [i for i in [1, 2, 3]]
print(generator) # <generator object <genexpr> at 0x10c312870>
print(next(generator)) # 1
print(next(generator)) # 2
print(next(generator)) # 3
print(next(generator)) # raise StopIteration
- yield
1
2
3
4
5
6
7
8
9
10
11def getGenerator():
for i in [1, 2, 3]:
yield i
print("done")
generator = getGenerator()
print(generator) # <generator object getGenerator at 0x10c3128c0>
print(next(generator)) # 1
print(next(generator)) # 2
print(next(generator)) # 3
print(next(generator)) # done & raise StopIteration
原理
当yield
出现在函数中(yield只能定义在函数中),那么调用时不会直接运行函数而是返回一个生成器对象,生成器也是一个特殊的迭代器(实现了迭代器协议的对象)。
- 第一次调用
next()
函数,遇见yield
停下返回yield后面的内容 - 再次调用
next()
函数,从上次yield语句处恢复,如果还存在yield
则正常执行,否则函数体执行完毕抛出StopIteration
异常通俗的来说:yield相当于return,但yield会记住这个返回位置,再次执行会从这个位置开始。
生成器中send()
是和next()
一样能让生成器恢复执行的函数,不同的是send(arg)
函数可以传递参数
1 | def getGenerator(): |
注意第一次调用生成器不可以直接传递非None参数,因为yield还未准备好(无返回值),可以generator.send(None)
或next(generator)
。具体可以参考python源码:
1 | const char *msg = "can't send non-None value to a " |
https://github.com/python/cpython/blob/3.9/Objects/genobject.c#L181
迭代协议
什么是可迭代协议?
当处理迭代时首先调用
可迭代对象.__iter__()
,返回迭代器。然后通过迭代器.__next__()
获取迭代器的元素,直至抛出StopIteration
。
1 | class CustomGenerator: |