免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2786 | 回复: 0
打印 上一主题 下一主题

Python generator和yield [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-01-12 16:32 |只看该作者 |倒序浏览

                generator归根到底是一个函数的返回值,这个函数是包含“yield”关键字的python函数。
是不是可以这么说(不是很确定,似乎可以这么理解)
1,凡包含“yield”关键字的函数,都返回generator
2,generator不是函数,而是函数执行后构造的对象,是一种iterator。
3,generator可以像iterator一样的用。
generator的根源是PEP 255,其中列出了generator在Python存在的原因,简单的讲,Generator在需要时返回中间值,能够保存当前的状态,等待下一次的返回要求。
xrange/range的区别或许可以帮我们理解这一点,xrange之所以存在,是因为range需要一次完成列表的初始化,存储等等,从C的角度来理解,就是,用range等于先malloc足够的内存,然后完成值的准备,等待调用(遍历等等)。而xrange则不这么干,什么时候要的时候,什么时候给值。所以,在Python 2.x中,type(range(10))是一个List,是内存中的静态数据;而type(xrange(10))则是一个range type。
到Python 3.x,xrange彻底替代了range函数。
这样设计的目的无非就是节省内存 ,千八百数字的无所谓,但ython 2.x的long int和Python 3.x的Int是无限制(用官方语言来说就是可以占满内存)。
generator为了满足这种需求设计的,状态得到了保存,随取随算。
PEP 255有一句: a Python generator is a kind of Python iterator[1], but of an especially powerful kind.
Python的产生器就是一种迭代器...
因为它是一种迭代器,所以,他可以用到for等控制流中。
def gen():
    print "one"
    yield 1
    print "two"
    yield 2
    print "three"
    yield 3
type(gen)
type(gen())
可以看到gen是函数,而gen()是generator,应该说,函数gen执行的返回值是生成一个generator。
generator的方法之一就是next()。
a=gen()
a.next()
a.next()
a.next()
a.next()
三次next,分别返回了1,2,3,最后一次,已到达末尾,发生StopIteration错误。
而yield的作用就是,每次发生next()调用,函数执行完yield语句之后在挂起,这时返回yield的值(你原因yield啥就yield啥),整个函数状态被保存,等待下一次next()调用;
下次next()调用发生时,从yield后的语句开始执行(有yiled也在循环体内,未必一定是顺序的),直到再次遇到yield为止,然后重复删除动作。
yield 可以解读为"返回然后等待"。知道所有yield语句完成,这时如果再次调用next(),则发生StopIteration异常,当然,在for循环之类的语句中会被自动处理。
yield
[jiːld]
n. 生产量,投资收益
vt. 生产,给予,同意,被迫放弃,放纵
vi. 出产,屈服,投降
在这里,当然是“生产”的意思。
PEP 255详细解释了为什么是"新关键字" yield,而不是return 变体等等的原因。
我想,一个简单的原因可能是return已经被大家清楚、牢靠的理解成了"函数的结束并返回“,而不是”返回并挂起“。
而在generator中(严格的说应该是返回值为generator的函数中),return仍然是这个意思。但,这里有个小小的要求,return不能返回任何值,哪怕是None。而return的作用跟其他地方一样,“返回”。
def g():
    print "one"
    yield 1
    print "two"
    yield 2
    print "three"
    return
    yield 3
a=g()
a.next()#yield 1
a.next()#yield 2
a.next()#return and raise StopIteration
这里的return,作的事情是返回(表示iterator用光)并产生raise StopIteration异常。
如果在yield中产生了任何异常,则直接传递给调用者,generator无法再次唤醒。
比如:
def err():
    raise KeyError
def gen():
    yield err()
    yield 2
a=gen()
a.next()#引发异常,KeyError
a.next()#引发StopIteration异常,并不是2。
在Python 3.x中,obj.next()被修改为next(obj),这是需要注意的一点。
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/72995/showart_1793801.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP