孙行者定身术+时间机器-Generator in Python(正文)

本文通过对比C语言中计算斐波那契数列的传统方法与Python中使用Generator的现代方法,阐述了Generator如何节省内存并提高效率。介绍了Generator的工作原理及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

书接上回,为什么需要coroutine?我们采用一个经典而浅显的案例:计算Fibnacci数列。翠花,上代码(C代码):

void get_fib(int n, int* result)

{
int i = 0;
for (i = 0; i < n; i++)
{
if (i < 2)
{
result[i] = i;
continue;
}
result[i] = result[i - 1] + result[i - 2];
}
}

上述代码中,参数n指定生成Fibnacci数字的个数,result为存放结果的buffer。这种写法是常见套路之一。我不必细说你就可以想象出调用处是怎样使用这个函数的。这是传统函数的套路。它有一个比较烦人的地方,就是存储空间的管理。如果数列规模n比较大,你不得不很不情愿地准备一个很大的空间用于存储,还可能一直提心吊胆地担心内存溢出或泄漏。

OK, 现在该轮到generator出场了。翠花,上代码(Python):

函数定义处:
def get_fib():

a, b = 0, 1

while 1:

yield b

a, b = b, a+b

函数调用处:

fib = get_fib()

for num in fib:

print num

注意,在这里你看不到准备存储空间的代码,因为确实没有这个动作。同时,yield登台亮相了。

Python版的这个”虚伪”的函数get_fib,在调用语句“fib = get_fib()”中,它其实并未被执行,而是构造并返回了一个被称为generator的对象,然后它被用在接下来的for循环中,用于枚举和打印fibnacci数(想要多少要多少,直到你主动退出循环)。按照官方的说法,这个generator的本质是一个迭代器(iterator),一个对象,它暗含了一个next()方法,该方法在for循环中被隐式调用。for循环每调用一次next方法,get_fib()函数的代码才被真正执行一次,但执行中遇到yield语句后就挂起,紧随yield其后的表达式b被作为本次返回值返回给调用者,本次运行结束。下一次next()再被调用,再从冻结处继续执行。也就是说,每次运行它都只运行函数体的一部分而不是全部,并且能够自动记忆前次停止的位置以便下一次从那里继续执行。

该怎样来认识generator的本质呢?其实,它就像是一个被动吐泡泡的机器,你碰它一下(调用next()方法),它就吐一个泡泡,不碰则不吐。我想这就是其名称“generator”的来历吧,因为它就负责不断地generate数据给调用者。因此,它不需要事先准备好一大块空间存放一堆泡泡,任意时刻它只产生一个泡泡!!!Python的官方文档说,generator是一个轻量级的coroutine实现。Wiki中的coroutine词条说coroutine是一个有多个入口、可以多次挂起和恢复执行的subroutine。这两个解释,和你在本例中看到的完全一致。按我个人的理解,在应用层面上看,generator是采用了时间换空间的策略,即用多次执行的代价换取了节省大片存储空间的好处。对于Fibnacci这个特别简单的例子,如果在C版本中增加若干局部static变量应该可以近似地模拟出来。

那么,这样的时空互换策略真的值得吗?有普遍应用的意义吗?这也是我怀疑的一点。别跟我一样孤陋寡闻。按照Wiki以及有识者的介绍,generator非常实用且应用非常广泛甚至可用在系统编程级别,例如合作性任务(生产者消费者问题)、迭代器、无穷列表(你没法事先准备足够大的空间)、实现pipe。而且,表面上就有一个显著的优势:你不必等所有数据都准备好才开始处理,有一个就处理一个。在读取特别大的文件时,generator也是非常好用的手法。有一位貌似比较资深的工程师提到,利用generator可以很容易地实现Unix编程中非常典型的pipeline架构,有兴趣深入的话,我建议你看看这里

后记:

我知道即使我这样仔细的举例说明,第一次接触它的人还是不一定能够真的理解。因为这里边的确有编程理念上的冲击。你不能抱着对传统函数的理解不放,这将成为理解generator和coroutine的最大障碍。不过,不要灰心,一次不行就多来几次,可以在网络上多看些相关文章(我建议你尽量看英文的或limodou的解释),或者来找我聊聊,我可以给你演示一些更生动的例子。

你可能会不屑于花费时间和精力来学些这么一个看似怪诞的东西,但是,我亲身的体会是,这宝贝真的值得你花时间来学习一下,即使你是一个老家伙。学习它将会非常有益于扩展你的技术视野以及编程理念,是一种显著的提高。真的,我不忽悠。等你掌握了定身术和时间机器的时候,你一定得请我吃一顿。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值