免费注册 查看新帖 |

Chinaunix

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

python(23): 发生器和循环器(14.6) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-03-31 21:45 |只看该作者 |倒序浏览
好久没有看书了。先是“两会”开了,我也像代表委员们一样忙,没有心情写。后来又是人一贯的惰性在起作用。以至于到了月底了,才觉得应该再看看书。还好对于是月份来说也算是有始有终。
发生器函数其实也是一种函数,用def来定义。当然跟一般的函数是不一样的。首先,普通函数既可以用def来定义,也可以用lambda来定义。而“发生器函数”应该只能用def来定义。其次,一般的函数在被调用的时候会用return语句返回一个值,然后退出。而发生器在被调和的时候,会返回一个叫做“发生器”类型的对象。
现在想象一下,用def定义了一个函数。那么,解释器怎么知道这是一个发生器函数呢。其实也很简单,一个发生器函数必然会包含一个或多个yield语句,当解释器碰到这样的函数时,就会知道这是一个“发生器函数”。下面通过一个简单的例子来了解具体的运行情况:
  • def gen(x):
  •     for i in range(x)[2:]:
  •         yield i
  •         yield i**2
  • x = gen(5)
  • x.next()===>2
  • x.next()===>4
  • x.next()===>3
    解释器在运行这段程序的时候,首先可以断定这是一个“发生器函数”,因此x这时为一个“发生器”类型的对象(generator object)。 这种对象具有一个next()方法,用来获取相应的值。这里就可以看到发生器的最大特点。看第6行,当运行到这行的时候,对应的是gen函数中的第3行,取得值2。这里解释一下,x取值5,因此range(x)为[0,1,2,3,4],而range(x)[2:]就为[2,3,4]。来看第7行,当next方法再次被调用的时候,gen并不是从头开始执行,它是从上一个yield语名后开始执行,也就是第4行,所以得值4。可以看出,next方法就相当于让yield函数执行到下一条yield语句,如果没有下一条yield语句了,那么就返回StopIteration异常。
    在上面的例子中,我们使用了next方法来显式地控制“发生器函数”一个一个地“发生”值。其实发生器函数更多的时候是用在”循环“的语境中,比如for语句、map()函数、list再构造等。当使用在这些语句中时,并不需要显式地调用next方法。 比如:
  • for i in x:
  •     print i
    下面来说说”循环器“。循环器也是一种对象,它由内置于函数iter()产生。这种对象也有一个next方法。作用与”发生器“对象中的next相同。由于在python中,一切皆对象。比如D为一个dict,iter(D)实际上只是调用了D中的__iter__函数。所以,如果自己定义一个类,只要这个类有__iter__函数,能产生”循环器“对象,那么这个类的对象就完全可以使用在像for语句这样的循环语境中。
    最后说一句,发生器实际达的效果是返回一组值。这种功能可以使用return语句返回一个序列(list dict tuple)来实现。但是如果当这个序列太大时,相信用”发生器“是一个更好的选择。因为,这样的话就没有必要把一大堆的东西放到内存中。
                   
                   
                   

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

    本版积分规则 发表回复

      

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

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP