python中迭代器(转)
一、迭代器与for语句
网上许多文章说Python的for语句中,in关键字后面的对象是一个集合。例如
for i in [1,2,3]
print i
上面代码中in关键字后面的对象[1,2,3]是一个list,也是一个集合。
但in关键字后面的对象其实不必是一个集合。后面接一个序列对象也是合法的。 例如
myrange = MyRange(0, 10)
for i in myrange:
print i
上面代码中的myrange对象是一个序列对象,但不是集合。参见上一篇博文。
事实上,for语句中in关键字后面的对象也不必是序列对象,它只需要是一个可迭代对象(Iterable)即可。
一个可迭代的对象需要满足下面两个条件之一:
- 它实现了__iter__方法。该方法会返回一个迭代器对象。
- 或者它是一个序列对象。
注意:如果一个类型实现了__iter__方法,那么在该方法中显式地给出了与该类型相关的迭代器如何构造。可是,对于序列类型来说,它有一个很天然的迭代器。因此,无需通过实现__iter__方法来显式定义。下一篇博文将介绍如何通过序列对象构造天然的迭代器。这里先介绍迭代器对象的严格定义。
一个迭代器,本质上也是一个序列。它需要实现下面两个方法。
- next方法(老版本的Python叫__next__方法)。当第11次调用next方法时,会返回序列的第1个元素;当第2次调用next方法时,会返回序列的第2个元素;当序列中的元素耗尽,抛出StopIteration异常。
- __iter__方法。前面说过__iter__方法通常返回迭代器对象。因此,对于一个迭代器来说,它的__iter__方法只需返回其本身即可。
通过上面的定义,我们知道,一个迭代器对象,也必是可迭代的。
下面的代码定义了一个迭代器。
class MyIterator:
def __init__(self, start, end):
self.start = start
self.end = end def next(self):
if self.start >= self.end:
raise StopIteration
self.start = self.start + 1
return self.start - 1 def __iter__(self):
return self
测试代码
myiter = MyIterator(0, 2)
print myiter.next()
print myiter.next()
print myiter.next()
输出结果如下
0
1
Traceback (most recent call last):
File "test.py", line 27, in <module>
print myiter.next()
File "test.py", line 16, in next
raise StopIteration
StopIteration
下面的代码测试在for语句中使用迭代器
myiter = MyIterator(0, 10)
for i in myiter:
print i
输出结果
0
1
2
3
4
5
6
7
8
9
二、iter方法
iter方法是Python的一个内建方法,它会返回一个迭代器对象。它定义如下
iter(o[, sentinel])
第一个参数o可以是一个可迭代对象,也可以是一个可调用对象。
当参数o是可迭代对象时,第二个参数可省。这里又分为两种情况。
- 如果参数o实现了__iter__方法,则直接调用该方法,创建迭代器。
- 如果参数o没有实现__iter__方法,那么它比是一个序列对象。iter方法根据该序列对象诱导出一个迭代器。
如果参数o是一个可调用对象时,iter方法返回的迭代器工作原理如下。
每次调用迭代器的next方法时,最终都会调用o方法。此时第2个参数sentinel必须给定。当o方法的返回值与sentinel相同时,抛出StopIteration异常。
一些例子
1. 由集合构造迭代器
myiter = iter([1,2,3])
myiter.next()
myiter.next()
myiter.next()
myiter.next()
输出结果
1
2
3
Traceback (most recent call last):
File "test.py", line 27, in <module>
print myiter.next()
StopIteration
2. 由序列对象构造迭代器。
myiter = iter(MyRange(1, 4))
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()
MyRange的定义见博文。
3. 由迭代器对象构造迭代器。
myiter1 = MyIterator(1, 4)
myiter2 = iter(myiter1)
print myiter1 == myiter2
MyIterator的定义见博文。上面代码输出的值为True。
4. 由可调用对象构造迭代器。
myiter1 = MyIterator(1, 4)
myiter2 = iter(myiter1.next, 4) print myiter2.next()
print myiter2.next()
print myiter2.next()
print myiter2.next()
输出结果
1
2
3
Traceback (most recent call last):
File "test.py", line 27, in <module>
print myiter.next()
StopIteration
有兴趣的读者可以尝试下面代码的输出结果。
myiter2 = iter(myiter1.next, 3)
print myiter2.next()
print myiter2.next()
print myiter2.next()
print myiter2.next()
myiter2 = iter(myiter1.next, 5)
print myiter2.next()
print myiter2.next()
print myiter2.next()
print myiter2.next()
三、for循环工作原理
对于如下的for语句
for obj in iterable_obj:
do something with obj
首先会调用iter方法获取关于iterable_obj对象的迭代器,然后不断调用迭代器对象的next方法,直至抛出异常位置。
为了说明这一点,看下面的例子。
myiter = MyIterator(1, 4)
for i in myiter:
pass print myiter.next()
上面代码会抛出StopIteration异常。因为在for语句阶段会将myiter迭代器对象的元素全部读完。MyIterator类的定义参见博文。
到目前位置,我们有三种方式表示一个序列。它们是集合,序列对象和迭代器对象。
- 集合(如列表,元组,字符串等)中的元素可读可写。当然不同的集合类型,可写的权限有所不同。例如列表中的元素可以随意添加,删除,修改。而元组中的元素虽然不能添加、删除和修改,但是我们可以对两个元组对象进行连接。当然,连接后会创建新的元组对象。
- 序列对象中的元素可读但不可写。在基本的定义中,两个序列对象也不必支持元组对象那样的连接操作。这样的好处是,在有的情况下,我们不必开辟专门的内存空间保存序列对象中的所有元素。
- 迭代器对象中的元素也是可读不可写的。但是,迭代器对读的权限做了一个限制,就是只能从头至尾读一遍。迭代器对象的优势在于它有的时候比序列对象更加灵活。通常情况下,序列对象中的元素顺序是不能变的。而对于迭代器对象来说,我们只需要指定不同的next方法,就能实现不同的读取顺序。一个比较经典的例子,就是我们可以实现一个迭代器类,同时支持树的深度优先和广度优先遍历。显然用迭代器实现这个功能比用序列来实现要简单许多。
四、序列诱导迭代器
如果我们自己要实现iter方法,通过一个序列对象构造出一个迭代器,会怎么做呢?
首先需要定义一个迭代器类。
class MyIteratorFromSequence:
def __init__(self, sequence):
self.start = 0
self.sequence = sequence def next(self):
if self.start >= len(self.sequence):
raise StopIteration
self.start = self.start + 1
return self.sequence[self.start - 1] def __iter__(self):
return self
上面的代码和博文中MyIterator类的定义完全类似,所不同的是,每次执行next方法,返回的不再是start - 1,而是序列对象的第start - 1个元素。
测试这个迭代器的运行效果
mylist = [1, 3, 5, 'a', 'b', 'c']
myiter = MyIteratorFromSequence(mylist)
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()
print myiter.next()
输出结果为
1
3
5
a
b
c
有了MyIterorFromSequence的定义,iter方法的实现就很简单了。
def myiter(sequence):
return MyIteratorFromSequence(sequence)
注意:上面的代码实现的功能比内置的iter方法要简单许多。因为我们只实现了序列对象到迭代器对象的构造。
有了上面的分析,下面代码的输出就在情理之中了。
mylist = [1, 2, 3]
myiter = iter(mylist)
mylist.append(4) for i in myiter:
print i
输出结果为
1
2
3
4
转自:http://blog.csdn.net/hedan2013/article/details/55519047
python中迭代器(转)的更多相关文章
- 关于Python中迭代器的作用
迭代器的定义:含有__iter__()方法和__next__()方法的就是迭代器,即(iterate) 含有__iter__()方法就可以使用for循环,即iterable(可迭代的) Iterabl ...
- 为什么for循环可以遍历list:Python中迭代器与生成器
1 引言 只要你学了Python语言,就不会不知道for循环,也肯定用for循环来遍历一个列表(list),那为什么for循环可以遍历list,而不能遍历int类型对象呢?怎么让一个自定义的对象可遍历 ...
- python中迭代器和生成器
l=[1,2,3,4] for n in l: print n 在看上面这段代码的时候,我们没有显式的控制列表的偏移量,就可以自动的遍历了整个列表对象.那么for 语句是怎么来遍历列表l的呢?要回答这 ...
- python中迭代器和生成器的区别
#!/usr/bin/python def power(values): for value in values: print "powing %s" % value yield ...
- python中迭代器和生成器。
前言:很多python教程中,对python的解释不容易理解,本文记录自己的理解和体会,是对迭代器和生成器的初步理解. 迭代器: 迭代器的实质是实现了next()方法的对象,常见的元组.列表.字典都是 ...
- python中迭代器和生成器的详细解释
https://www.cnblogs.com/wilber2013/p/4652531.html
- Python:迭代器的简单理解
一.什么是迭代器 迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样).迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序 ...
- for和while——python中的循环控制语句详解
循环语句在绝大多数的语言中,都是必不可少的一种控制语句,循环语句允许我们执行一个语句或语句组多次.在python中有for循环和while循环两种,讲到这里,就不得不提到我们的迭代器对象 迭代器 迭代 ...
- Python中的迭代器和生成器
本文以实例详解了python的迭代器与生成器,具体如下所示: 1. 迭代器概述: 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后 ...
随机推荐
- CC2530中串口波特率改为9600时单个数据包来不及接收的解决方案
在调试CC2530过程中发现波特率改为9600时,单个包仅有3个Byte时,接收DMA就会启动 因而数据包被强迫拆分成多个,显然只要将接收DMA启动延时做到足够大即可. 具体修改内容如下图所示: 经过 ...
- OpenWrt在没有Luci时刷机
scp上传bin文件到root文件夹下. sysupgrade openwrt-ar71xx-generic-dragino2-squashfs-sysupgrade.bin 等待重启
- SQL 实践和技巧 <2>
转自 http://i.cnblogs.com/EditPosts.aspx?opt=1 几个小技巧 (1)||的使用: select ‘(‘||phone[1,3]||’)’phone[5, ...
- [记录]js跨域调用mvc ActionResult扩展
背景 最近2个项目中都用到了js跨域访问的知识,2个项目都需要主站与各个分站之间进行数据交互.状态同步等相关操作.浏览器本身是不允许进行跨域访问,在MVC中我们可以扩展一个方法来实现这个功能.在此大家 ...
- Sublime Text 3 最新可用注册码(免破解)
12年的时候分享过Sublime Text 2的注册码和破解方法.4年后容我更新一下Sublime Text 3的注册码.. 最好还是购买正版主持版权.:D. 以下两枚注册码用最新的Sublime T ...
- Hadoop高级培训课程大纲-开发者版
一.课程概述 本次培训课程主要面向大数据系统管理人员和开发设计人员,基于开源社区大数据应用最活跃的Hadoop和HBase技术框架,围绕分布式文件存储(HDFS).分布式并行计算(Map/Recue) ...
- 有意思的bug
1. Xss攻击型的bug Xss攻击即跨站脚步攻击,通过插入恶意脚本 ,实现对用户浏览器的控制. Bug现象:新增物品时,物品名称输入一段JavaScript代码,在提交时此代码被执行.如:输入&l ...
- HUD 1175 连连看
连连看 Time Limit : 20000/10000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total Submiss ...
- 配置Samba(CIFS)
试验环境:一台CentOS 7.0的虚拟机,一台Windows 的普通台式机. 注意:网络一定能够ping通 关闭SeLinux # setenforce 0 # getenforce 关闭防火墙 # ...
- 【Gearman学习笔记】分布式处理入门
1.首先,确保你已经安装了gearmand环境并且语言绑定(language binding)已经生效. 2.涉及到的各个部分: ServerThe server, gearmand, will co ...