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