python中的generator

怎么用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异常,程序会正常结束。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值