首页 > Python基础教程 >
-
深入理解Python生成器(Generator)
我们可以通过列表生成式简单直接地创建一个列表,但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,而且如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
1
2
3
4
5
6
|
>>> mylist = [ x for x in range(1, 10)] >>> mylist [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> gen = (x for x in range(1,10)) >>> gen <generator object <genexpr> at 0x7f1d7fd0f5a0> |
创建mylist和gen的区别仅在于最外层的[]和(),mylist是一个list,而gen是一个generator(生成器)。
我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?
如果要一个一个打印出来,可以通过generator的next()方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> gen.next() 1 >>> gen.next() 2 >>> gen.next() 3 ... >>> gen.next() 9 >>> gen.next() Traceback (most recent call last): File "<stdin>" , line 1, in <module> StopIteration |
我们讲过,generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
其实我们可以使用for循环来代替next()方式, 这样才更符合高效的编程思路:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> gen = ( x for x in range(1, 10)) >>> for num in gen: ... print num ... 1 2 3 4 5 6 7 8 9 |
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1
|
1, 1, 2, 3, 5, 8, 13, 21, 34, ... |
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
1
2
3
4
5
6
7
|
def fib( max ): n = 0 a, b = 0 , 1 while n < max : print b a, b = b, a + b n = n + 1 |