python中的generator

来源:互联网 发布:淘宝没有3c会怎么样 编辑:程序博客网 时间:2024/06/03 16:50

怎么用python实现一个斐波那契数列?新手们很容易这样写:

def fab(max):    n, a, b = 0, 0, 1    while n < max:        print b        a, b = b, a+b        n += 1
这样可以正确的获得斐波那契数列,但是在函数中,用print打印数字导致函数复用性较差。因为fab函数没有返回值,其他函数没法得到通过fab函数产生的数列。

针对这个问题的一个改进办法,就是不直接打印出来,而是返回一个List,于是可以写成这样:

def fab(max):    n, a, b = 0, 0, 1    result = list()    while n < max:        result.append(b)        a, b = b, a+b        n += 1    return result

然后通过以下方式打印出list中的数字:

for n in fab(5):    print n

这样增加了函数的复用性,但随之而来另一个问题,内存占用会随着max的值增大而增大,如果要控制内存占用,不推荐使用List。

要保存中间结果,可以通过iterable对象来迭代。例如:

for x in range(1000): pass
上面这段代码会生成一个含1000个元素的list,而:

for x in xrange(1000): pass
则不会生成一个List,而是在在每次迭代时返回下一个数值,内存占用空间很小。xrange返回的就是一个iterable对象。

因此,针对上面的问题,可以把fab函数改进成为一个支持iterable的class。

class Fab(object):    def __init__(self, max):        self.max = max        self.n, self.a, self.b = 0, 0, 1    def __iter__(self):        return self    def next(self):        if self.n < self.max:            r = self.b            self.a, self.b = self.b, self.a + self.b            self.n += 1            return r        raise StopIteration()

Fab类通过调用next()函数不断返回数列中的下一个数,内存占用始终是一个常数。

for n in Fab(5):    print n
但是这段代码和之前的代码比较起来,显得没那么简洁。为了保存代码的简洁,又要获得iterable的效果,yield就派上用场了。

def fab(max):    n, a, b = 0, 0, 1    while n < max:        yield b        a, b = b, a+b        n += 1
这段代码只是把第一段代码中的print b改成了yield b,就有了iterable的效果。调用方式为:

for n in fab(5):    print n
此处,yield的作用就是把一个函数变成一个generator,带有yield的函数不再是一个普通函数,python解释器会将其视为一个generator,调用fab(5)不会执行fab函数,而是返回一个可迭代对象。在for循环执行时,每次循环都会执行fab函数内部的代码,执行到yield b时,fab函数就返回一个迭代值,下次迭代时,就会从yield b的下一条语句继续执行,函数中的本地变量和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到yield。

可以通过手动调用fab(5)的next()方法,看到具体的执行流程。

>>> f = fab(5)  >>> f.next()  1  >>> f.next()  1  >>> f.next()  2  >>> f.next()  3  >>> f.next()  5  >>> f.next()  Traceback (most recent call last):   File "<stdin>", line 1, in <module>  StopIteration
当函数执行结束时,generator自动抛出StopIteration异常,表示迭代完成。在for循环中,无需处理StopIteration异常,程序会正常结束。





0 0
原创粉丝点击