文档章节

Python中的迭代器与生成器

lionets
 lionets
发布于 2013/11/21 21:46
字数 999
阅读 1434
收藏 13

container.__iter__()  和 iterator.__next__()

迭代器就是一个有 __next__() 方法的对象。当需要下一个数据时,调用它的 __next__() 方法就可以获得。在Python2中,这个方法被命名为 next() 。但在Python3中新增加了内建的 next() 函数,就像用来调用 __iter__() 的 iter() 函数一样,next() 也是用来调用 __next__() 的。

就如上面所说,对迭代器来讲,有一个__next__()就够了。在你使用for 和 in 语句时,如果可行,程序就会自动调用即将被处理的对象的迭代器对象,然后使用它的__next__()方法,直到监测到一个StopIteration异常。以比较常用的 range() 来举例:

>>> type(range(10))
<class 'range'>
>>> next(range(10))
Traceback (most recent call last):
  File "<pyshell#163>", line 1, in <module>
    next(range(10))
TypeError: 'range' object is not an iterator
>>> type(iter(range(10)))
<class 'range_iterator'>
>>> next(iter(range(10)))
0

我们可以看到,range(10) 本身作为一个 <class 'range'> 对象是不可迭代的,但是 iter(range(10)) 或者说 range(10).__iter__() 可以,它的类(型)是<class 'range_iterator'>,它有 __next__() 方法。那么如何使用迭代器看起来就变得简单了——我们只要在类里面定义一个 __iter__() 函数,用它来返回一个带 __next__() 方法的对象就够了。其实按照官方文档的说法,迭代器对象里也应该有一个 __iter__() 方法,这个方法只需要一个语句 return self ,这是为了保证在使用 for 语句时,容器对象和迭代器对象都可以被正确调用,就像下面这样:

>>>for x in container:pass 
>>>for x in iter(container):pass

__iter__() 的设计非常简单,因为我们大可以把 self 返回,然后在类里面定义 __next__() 。这样定义的一个类,其自身既是容器,又是迭代器(真棒)。那么接下来的主要问题就是设计 __next__() 了。

我们使用斐波那契数列来举例:

class Feb:
    def __init__(self):
        self.pre = 1
        self.num = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.num < 10:
            self.pre,self.num = self.num,self.pre+self.num
            return self.num
        else:raise StopIteration

试运行如下:

>>> feb = Feb()
>>> for i in feb:
	print(i)

1	
1
2
3
5
8
13
>>>

嗯,还算正常。for 循环正确迭代了 Feb 实例,正确处理了 StopIteration 异常。只是有一个小Bug,我本来没想让它输出13来着…

我们可以看到这个 __next__() 实现的不很好,它看起来很麻烦。那么如何“优雅”地实现迭代器呢?当然就是用“生成器”啦!

generator.__next__() 和 generator.send() 和 generator.close()

生成器是一个特定的“函数”,当调用时它返回一个生成器对象(所以你不能在定义生成器的时候 return 任何值,但可以使用单独的一个 return ,它代表进度结束)。生成器允许你返回一个值,然后暂停代码的执行,稍后恢复,可以这样重复 n 次。实现这一“优雅”效果的关键字就是 yield

还是斐波那契数列:

def feb():
    pre = num = 1
    yield pre
    yield num
    while True:
        pre, num = num, pre+num
        if num<10:
            yield num
        else:return

输出如下:嗯,这次没有10以上。

>>> a = feb()
>>> for i in a:
	print(i)

	
1
1
2
3
5
8
>>>

值得一提的是,这种协同程序是可以在 yield 值出来的时候顺便回传一个参数(或异常)的,它定义时的语法是:foo = (yield bar) 。当程序把 bar 返回出来的时候,程序挂起。这时可以通过使用 generator.send() 方法来给实例里的foo赋值。如果你不想再迭代了,还可以使用 generator.close() 方法来关闭生成器。

下面是一个从可由用户定义的整数 n 开始不断返回 n+1 的生成器:

def plus1(n=0):
    n = n
    while True:
        var = (yield n)
        if var:
            n = var
        else:n += 1

>>> a = plus1()

>>> for i in a: if i>3:break else:print(i) 0 1 2 3 >>> a.send(100) 100 >>> for i in a: if i > 103:break else:print(i) 101 102 103 >>> a.close() >>> next(a) Traceback (most recent call last): File "<pyshell#230>", line 1, in <module> next(a) StopIteration >>>

© 著作权归作者所有

共有 人打赏支持
lionets
粉丝 91
博文 98
码字总数 132850
作品 0
朝阳
程序员
Python3+迭代器与生成器

转载Python3 迭代器与生成器 迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的...

xinet
2017/08/12
0
0
Python3 迭代器与生成器

迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只...

Eappo_Geng
04/05
0
0
Python知识点总结篇(四)

递归 特性 - 必须有明确的结束条件; - 每进入深一层递归,问题规模比上层应有所减少; 递归效率不高,层次更多会导致栈溢出; 函数式编程 计算机:在计算机层面,CPU执行的是加减乘除以及各...

村雨1943
10/03
0
0
Python的三大神器,你知道是哪三大吗?史上最详细的入门教程!

Python的三大神器:装饰器.迭代器与生成器!这就是Python的三大神器,好了废话不多说。直接来上干货吧! 生成器 仅仅拥有生成某种东西的能力,如果不用next方法是获取不到值得。 创建一个生成...

q1622479435
06/08
0
0
更深入的理解 Python 中的迭代

深入探讨 Python 的 循环来看看它们在底层如何工作,以及为什么它们会按照它们的方式工作。 Python 的 循环不会像其他语言中的 循环那样工作。在这篇文章中,我们将深入探讨 Python 的 循环来...

01%
05/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

WinDbg

参考来自:http://www.cnit.net.cn/?id=225 SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols ctrl + d to open dump_file Microsoft (R) Windows Debugger Version 6.12.0002.633......

xueyuse0012
今天
2
0
OSChina 周五乱弹 —— 想不想把92年的萝莉退货

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @罗马的王:分享松澤由美的单曲《地球ぎ》 很久没看圣斗士星矢了 《地球ぎ》- 松澤由美 手机党少年们想听歌,请使劲儿戳(这里) @开源中国首...

小小编辑
今天
14
1
springBoot条件配置

本篇介绍下,如何通过springboot的条件配置,控制Bean的创建 介绍下开发环境 JDK版本1.8 springboot版本是1.5.2 开发工具为 intellij idea(2018.2) 开发环境为 15款MacBook Pro 前言 很多时候,...

贺小五
今天
1
0
javascript source map 的使用

之前发现VS.NET会为压缩的js文添加一个与文件名同名的.map文件,一直没有搞懂他是用来做什么的,直接删除掉运行时浏览器又会报错,后来google了一直才真正搞懂了这个小小的map文件背后的巨大...

粒子数反转
昨天
1
0
谈谈如何学Linux和它在如今社会的影响

昨天,还在农耕脑力社会,今天已经人工智能技术、大数据、信息技术的科技社会了,高速开展并迅速浸透到当今科技社会的各个方面,Linux日益成为人们信息时代的到来,更加考验我们对信息的处理程...

linux-tao
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部