首页 > 代码库 > 生成器&迭代器
生成器&迭代器
通过列表生成式,我们可以快速创建一个列表,但是受到内存的限制,列表容量是有限的,而且一个包含100万个元素的列表不仅占用很大的存储空间,如果我们仅仅需要访问当前几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以如果列表元素可以按照某种算法推算出来,那我们是否可以在循环中的过程不断推算出后续的元素呢?就不必创建完整的列表了,从而节省大量的内存。在python中一边循环一百年计算的机制成为生成器:generator。
要创建一个generator,有很多方法,第一种方法最简单,只要把列表生成式的[]改为() ,就创建了一个generator:
L = [x * x for x in range(10)] print(L) 打印结果:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] g = (x * x for x in range(10)) print(g) 打印结果: <generator object <genexpr> at 0x1022ef630>
可以通过next()
函数获得generator的下一个返回值:
next(g)
next(g)
next(g)
next(g)
next(g)
结果:
0
1
4
9
16
generator保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return ‘done‘
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
举个简单的例子,定义一个generator,依次返回数字1,3,5:
def odd(): print(‘step 1‘) yield 1 print(‘step 2‘) yield(3) print(‘step 3‘) yield(5)
生成器&迭代器