VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 深入理解Python生成器(Generator)

我们可以通过列表生成式简单直接地创建一个列表,但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,而且如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

 

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

1
2
3
4
5
6
>>> mylist = [ x for in range(1, 10)]
>>> mylist
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> gen = (x for 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 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):
    = 0
    a, b = 01
    while n < max:
        print b
        a, b = b, a + b
        = + 1

相关教程