生成器是进入python更高层次一个很重要的概念,这里用一个小例子简单记录一下
借用一个生成斐波那契数列的python代码进行解释,这是一般的写法:
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
for n in fab(5):
print n
这个写法定义了一个函数,把传入的参数作为斐波那契数列的长度,将整个数列运算完成之后,返回一个列表。这样做虽然没错,但是我们可以发现,随着传入的参数变大,数列占用内存的体积也将慢慢变大。
于是为了提高效率,出现了这么一种思想,既然数列是有规律的,那么可不可以在需要下一个值的时候再进行运算,在不需要的时候就停止计算,以此可以保证内存占用始终为常数。
这就涉及到了python中 "协程" 的概念。总所周知,在一个线程中子程序的调用建立在栈的基础上,携程简而言之就是可以在同一个线程中,在一个子程序未执行完毕的情况下去执行另一个子函数。这种执行方式不需要复杂的锁,所以可以提高多线程的效率。
回到正题,python提供了一种叫生成器的东西,只要在定义函数时使用yield “替代” (并不是简单的替代)return 即可获得一个生成器。
def func(a):
......
yield x
......
当调用这个函数的时候会创建一个generator对象,这个对象具有next()方法。每执行一次next()方法,子程序会把语句执行到yield的位置,返回一个值,然后被挂起,转而继续执行原来的子程序。而当再次调用next()方法时会接着yield往下执行,直到抛出 StopIteration,也就是终止迭代。
同样还是生成斐波那契数列,用生成器的方法:
from inspect import isgeneratorfunction
def func(max:int=9):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n+=1
print(isgeneratorfunction(func))
a = func(10)
print(type(a))
for i in a:
print(i)
注意isgeneratorfunction 用于检测一个函数是不是生成器函数
这里使用a=func
是实例化的出了一个generator对象,实际上每次实例化得到的对象都是不一样的,它们互不影响,也就是面向对象编程的特点。