通过列表生成式我们可以方便的生成列表。但是在有的时候,我们需要生成的列表非常长,而我们的计算机的内存是有限的。在操作列表的时候,我们往往只是操作了列表的一部分区域的数据。

例如我们需要生成这么一个列表,列表中除了第1个和第2个数字外,其余数字都是前两个数之和。

1,2,3,5,8,13...

如果这个数组只有几千个或者几万个数字的时候,我们或许还能将它们都生成存在内存中。但是我们如果需要连续计算几千万个数字的时候,我再按上面的思路来就不大现实了。

认真思考一下上面的数列,我们在遍历的时候,其实只要知道前两个数字的数值,我们就能源源不断地计算出下一个数值是多少。

Python其实已经给我们提供了现有的工具让我们生成数列。与之前的生成式不同,生成器(Generators)在定义的时候并不是直接在内存中生成数列,而是定义一个生成数列的算法。

定义列表生成器有两种方式,一种是算式列表生成器(我起的名字),一种通过yield关键词。

算式列表生成器

算式列表生成器雨列表生成式类似,但[]需要换成()

my_gernerator = (x*x for x in range(1,101))

generator object的迭代方式

1. next()函数

我们可以调用generator object的next()函数让指针下移。例如

print my_generator.next() #输出 1
print my_generator.next() #输出 4
print my_generator.next() #输出 9

每调用一次next(),计算出一个值,并记忆迭代到何处了。当迭代到最后一个元素后再调用next(),python则会抛出StopIteration错误。我们可以捕获这个错误来处理迭代终止。
next()这种手动调用的运用较少。

2. 用for循环

我们可以利用collections.Iterable来判断generator object是否是一个Iterable对象。

from collections import Iterable
g = (x**3 for x in range(1,101))
print isinstance(g, Iterable) #输出True

因此我们可以用for迭代generator object

for item in g:
    print item

包含yield的函数定义列表生成器

在定义一个比较复杂的列表生成器的时候,上述算式型的列表生成器已经不能满足我们的需求了。我们可以用一个包含yield关键字的函数来定义一个列表生成器。
例如我们来实现一下文章开头生成一个“每个数字都是前两个数字之和”的数列。

def fibonacci(max):
    n,a,b = 0,1,2
    while n<max:
        yield b #-----> Generator迭代到该处时,即产生一个数。并暂停在此处,等待下一次迭代,又从该处开始,又直到遇到下一个yield..不断反复,直到程序结束。
        a,b = b,a+b
        n = n+1

此时,fibonacci不再是一个普通函数,而是一个generator object
我们通常用for循环来迭代generator对象。

for n in fibonacci(10):
    print n

Char
506 声望34 粉丝

hello world