python中的生成器(generator)
生成器是python中一个非常酷的特性,python 2.2中引入后在2.3变成了标准的一部分。它能够让你在许多情况下以一种优雅而又更低内存消耗的方式简化无界(无限)序列相关的操作。
生成器是可以当做iterator使用的特殊函数,它功能的实现依赖于关键字yield,下面是它如何运作一个简单的演示:
yield"first"
yield"second"
yield"third"
>>> spam
<function spam at 0x011F32B0>
>>>for x in spam():
print x
first
second
third
>>> gen=spam()
>>> gen
<generator object spam at 0x01220B20>
>>> gen.next()
'first'
>>> gen.next()
'second'
>>> gen.next()
'third'
在函数spam()内定义了一个生成器,但是对spam()的调用永远只能获得一个单独的生成器对象,而不是执行函数里面的语句,这个对象(generator object)包含了函数的原始代码和函数调用的状态,这状态包括函数中变量值以及当前的执行点——函数在yield语句处暂停(suspended),返回当前的值并储存函数的调用状态,当需要下一个条目(item)时,可以再次调用next,从函数上次停止的状态继续执行,知道下一个yield语句。
生成器和函数的主要区别在于函数 return a value,生成器 yield a value同时标记或记忆 point
of the yield 以便于在下次调用时从标记点恢复执行。 yield
使函数转换成生成器,而生成器反过来又返回迭代器。
有三种方式告诉循环生成器中没有更多的内容:
- 执行到函数的末尾("fall off the end")
- 用一个return语句(它可能不会返回任何值)
- 抛出StopIteration异常
一个经典的例子是和C语言中的static语句相比较:在Python没有明确支持的所谓static变量,但是在函数之间相互调用时,生成器能让你能以一个更优雅的方式实现类似的效果:
在C语言中 fibonacci 函数的实现:
int main() {
printf("0\n");
printf("1\n");
while (1)
printf("%d\n",fib());
/* for test use*/
// int i=0;
// while(i<20){
// i++;
// printf("%d\n", fib());}
}
int fib() {
static unsigned first=0,second=1,next,retval;
next=first+second;
retval=next;
first=second;
second=next;
return retval;
}
python实现:
# -*- coding: utf-8 -*-
# filename: fib.py
def fib():
first=0
second=1
yield first
yield second
while1:
next=first+second
yield next
first=second
second=next
运行:
>>> fib()
<generator object fib at 0xb76fcfcc>
>>>import itertools
>>> list(itertools.islice(fib(), 10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
也可以用如下方式截取一部分输出(但建议使用 itemtools 模块):
... print num
上述 fibonacci 函数的实现看起来较为繁琐,更加简捷优雅的实现如下:
# -*- coding: utf-8 -*-
# filename: fib.py
def fib():
first, second=0, 1
while1:
yield second
first, second= second, first+second
注意:但是在C语言中由于static的特性,在一个函数体内当需要产生多组 fibonacci 数列时可能就需要定义相同的诸如fib1() fib2() fib3()的函数。python中可以利用上述函数构造任意多个独立的生成器对象。
至于生成器(generator)应该使用在哪些方面以便更好地节省内存——你可以使用在需要计算列表的值但是每次只需要访问一个item的地方,和预先计算好将其存储在一个列表里相比,生成器在运行中逐个计算其值(computes the values on the fly)。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有调度器的协程不是好协程,零基础深入浅出 C++20 协程
· 别做抢活的导演:代码中的抽象层次原则
· 从 Redis 客户端超时到 .NET 线程池挑战
· C23和C++26的#embed嵌入资源指南
· 「EF Core」框架是如何识别实体类的属性和主键的
· 阿里巴巴为什么禁止超过3张表join?
· 博客园众包线下沙龙第1期:云栖开发者基地,共建技术新天地
· 让 AI 帮我部署网站,太方便了!
· 别做抢活的导演:代码中的抽象层次原则
· .NET周刊【7月第1期 2025-07-06】