生成器是进入python更高层次一个很重要的概念,这里用一个小例子简单记录一下

0x00 什么是生成器

借用一个生成斐波那契数列的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 即可获得一个生成器。

0x01 生成器函数的工作原理

def func(a):
    ......
    yield x
    ......

当调用这个函数的时候会创建一个generator对象,这个对象具有next()方法。每执行一次next()方法,子程序会把语句执行到yield的位置,返回一个值,然后被挂起,转而继续执行原来的子程序。而当再次调用next()方法时会接着yield往下执行,直到抛出 StopIteration,也就是终止迭代。

0x02 示例

同样还是生成斐波那契数列,用生成器的方法:

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对象,实际上每次实例化得到的对象都是不一样的,它们互不影响,也就是面向对象编程的特点。

标签: none

添加新评论