python 生成器 generator

时间:2025-02-01 14:05:50

一、生成器定义

通过列表生成表达式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

 >>> l = [x * x for x in range(10)]
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1013e0780>

二、表达式生成器

创建l和g的区别仅在于最外层的[]和(),l是一个list,而g是一个generator。可以直接打印出l的每一个元素,打印出g的每一个元素需要使用next()函数。

 >>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1013e0780>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

 >>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
...
0
1
4
9
16
25
36
49
64
81

首先generator是可迭代对象,所以可以使用for in循环遍历。该遍历的本质是for in循环内部调用next()函数获取每一个元素,并且捕获StopIteration异常,结束遍历。

三、函数生成器

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易。

 >>> def fib(max):
... n, a, b = 0, 0, 1
... while n < max:
... yield b
... a, b = b, a + b
... n += 1
... raise StopIteration('done')
...
>>> fib(6)
<generator object fib at 0x1013e0780>
>>> for i in fib(6):
... print(i)
...
1
1
2
3
5
8
>>> g = fib(6)
>>> while True:
... try:
... next(g)
... except StopIteration as e:
... print(e.value)
... break
...
1
1
2
3
5
8
done