Python提供了一个高级特性: 生成器,顾名思义,生成器就是不断生成结果的对象;那生成器有什么好处呢?
假设我们现在需要对1亿以内的正整数做一个统计操作,那如果我们一次生成这么多整数,势必需要占用很大的内存空间,但是我们一次生成一个整数,然后下一次生成下一个整数,那么就只需要很少的内存即可,这里就是生成器的用武之地。
生成器在惰性计算或者延迟处理的场景下非常有用,也即需要的时候才会产生结果,而不是一次产生全部结果。
在Python中创建生成器有2个途径:
1. 生成器表达式,可列表解析类似,但是列表解析是一次产生一个结果列表,而生成器每次返回一个结果,因此我们无法用len来对生成器求取其长度
In [37]: mygen = (i for i in range(10))
In [38]: mygen
Out[38]: <generator object <genexpr> at 0x0000000004B84780>
In [39]: len(mygen)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-39-2543d0066a5c> in <module>()
----> 1 len(mygen)
TypeError: object of type 'generator' has no len()
2.生成器函数,通过函数定义生成器,返回结果使用yield而不是return,yield一次返回一个结果并挂起函数的状态,在下次取结果的时候从它上次离开的地方继续执行。
In [40]: def mygenfunc(n):
...: for i in range(n):
...: yield i
...:
In [41]: mygen = mygenfunc(3)
In [42]: mygen
Out[42]: <generator object mygenfunc at 0x0000000004AA2D58>
注意,生成器也是迭代器
In [43]: isinstance(mygen, Iterator)
Out[43]: True
这意味着我们用for对它进行遍历,或者使用next来获取下一个结果。
In [44]: for i in mygen:
...: print(i)
...:
0
1
2
遍历完后,使用next获取下一个结果会抛出StopIteration异常
In [45]: next(mygen)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-45-0168a806c5f8> in <module>()
----> 1 next(mygen)
StopIteration: