迭代器

迭代器是在python2.2中被加入的,它为类序列对象提供了一个类序列的接口。有了迭代器可以迭代一个不是序列的对象,因为他表现出了序列的行为。当在python中使用for循环迭代一个对象时,调用者几乎分辨不出他迭代的是一个迭代器对象还是一个序列对象,因为python让他(迭代器)像一个序列那样操作。

如何迭代

本质上说迭代器是个对象,但是这个对象有个特殊的方法next()(在python3中使用__next__()代替了next方法)。当使用for循环来遍历整个对象时候,就会自动调用此对象的__next__()方法并获取下一个item。当所有的item全部取出后就会抛出一个StopIteration异常,这并不是错误的发生,而是告诉外部调用者迭代完成了,外部的调用者尝试去捕获这个异常去做进一步的处理。

不过迭代器是有限制的,例如

不能向后移动
不能回到开始
也无法复制一个迭代器。
因此要再次进行迭代只能重新生成一个新的迭代器对象。
获取迭代器 对于python内置的可迭代(iterable)对象,可以通过内置的iter()函数来获取相应的迭代器对象。
Python a = [1,2,3,45]
type(a)
list
a = iter(a)
type(a)
list_iterator
1
2
3
4
5
6
7
8
9
a = [1,2,3,45]
type(a)
list
a = iter(a)
type(a)
list_iterator
这样就获取了list相应的迭代器对象。
我们来看一下该迭代器对象的属性:
Python dir(a)
['__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__iter__',
'__le__',
'__length_hint__',
'__lt__',
'__ne__',
'__new__',
'__next__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__setstate__',
'__sizeof__',
'__str__',
'__subclasshook__'] 可见此迭代对象具有两个特殊的成员方法__iter__()和__next__(),这两个方法便是支持迭代器协议所需要实现的方法。其中__iter__()方法返回迭代器对象本身,__next__()方法返回容器的下一个元素,直到结尾抛出StopIteration异常。 我们来测试一下这个list_iterator对象的这两个方法: __iter__()返回的对象就是迭代器对象本身。 Python a = [1,2,3,45] a = iter(a) a.__iter__()
<list_iterator at 0x3a33f10>a
<list_iterator at 0x3a33f10>a is a.__iter__()
True In [1]: a = [1,2,3,45] In [2]: a = iter(a) In [3]: a.__iter__()
Out[3]: <list_iterator at 0x3a33f10> In [4]: a
Out[4]: <list_iterator at 0x3a33f10> In [5]: a is a.__iter__()
Out[5]: True In [6]:
__next__()方法返回容器中的值直到结尾。 Python In [6]: a.__next__()
Out[6]: 1 In [7]: a.__next__()
Out[7]: 2 In [8]: a.__next__()
Out[8]: 3 In [9]: a.__next__()
Out[9]: 45 In [10]: a.__next__()
------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-10-73aa2c76d676> in <module>()
----> 1 a.__next__() In [6]: a.__next__()
Out[6]: 1 In [7]: a.__next__()
Out[7]: 2 In [8]: a.__next__()
Out[8]: 3 In [9]: a.__next__()
Out[9]: 45 In [10]: a.__next__()
------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-10-73aa2c76d676> in <module>()
----> 1 a.__next__() StopIteration: In [11]:
2. 创建迭代器对象 除了使用iter()函数将内置的序列对象转换成相应的迭代器,我们可以自己实现迭代器协议创建迭代器对象,要实现迭代器协议也就是要在类中实现__iter__()和__next__()方法。 下面我写一个与list_iterator相同行为的迭代器: Python class ListIter(object):
def __init__(self, data):
self.__data = data
self.__count = 0 def __iter__(self):
return self def __next__(self):
if self.__count < len(self.__data):
val = self.__data[self.__count]
self.__count += 1
return val
else:
raise StopIteration class ListIter(object):
def __init__(self, data):
self.__data = data
self.__count = 0 def __iter__(self):
return self def __next__(self):
if self.__count < len(self.__data):
val = self.__data[self.__count]
self.__count += 1
return val
else:
raise StopIteration
我们就可以使用for循环来遍历这个迭代器了: Python In [16]: a = ListIter([1,2,3,4,5]) In [17]: for i in a:
....: print(i)
....: In [16]: a = ListIter([1,2,3,4,5]) In [17]: for i in a:
....: print(i)
....: 对于迭代器对象,使用for循环遍历整个数组其实是个语法糖,他的内部实现还是通过调用对象的__next__()方法。
实际上他内部的工作原理应该是这样的: a = ListIter([1, 2, 3, 4, 5]) while True:
try:
i = a.__next__()
except StopIteration:
break
// do something in for loop
print(i)
a = ListIter([1, 2, 3, 4, 5]) while True:
try:
i = a.__next__()
except StopIteration:
break
// do something in for loop
print(i)
迭代器支持多次迭代 正如前面所说的迭代器对象不支持重新迭代,也就是同一个迭代器对象无法多次迭代,如: Python In [19]: a = ListIter([1,2,3,4,5]) In [20]: [i for i in a]
Out[20]: [1, 2, 3, 4, 5] In [21]: [i for i in a]
Out[21]: [] In [19]: a = ListIter([1,2,3,4,5]) In [20]: [i for i in a]
Out[20]: [1, 2, 3, 4, 5] In [21]: [i for i in a]
Out[21]: [] In [22]:
可见,当我再次迭代迭代器a的时候便只返回了空列表,这是因为for循环直接捕获了StopIteration异常。如果要再次迭代生成列表的话只能重新生成一个新的迭代器对象。
为了能够解决这个问题,可以分别定义一个可迭代对象(iterables)和迭代器对象(iterator). 插入小插曲: 对于可迭代对象和迭代器对象,我的理解是:
可迭代对象是实现了__iter__()方法的对象,__iter__()可以返回一个迭代器对象。
迭代器对象是实现了__next__()方法的对象,其中他的__iter__()返回的是迭代器对象本身。 我把代码做了修改,如下: Python class ListIterable(object):
def __init__(self, data):
self.__data = data def __iter__(self):
print("call iterable __iter__().")
return ListIterator(self.__data) class ListIterator(object):
def __init__(self, data):
self.__data = data
self.__count = 0 def __iter__(self):
print("call iterator __iter__().")
return self def __next__(self):
print("call iterator __next__().")
if self.__count < len(self.__data):
val = self.__data[self.__count]
self.__count += 1
return val
else:
raise StopIteration class ListIterable(object):
def __init__(self, data):
self.__data = data def __iter__(self):
print("call iterable __iter__().")
return ListIterator(self.__data) class ListIterator(object):
def __init__(self, data):
self.__data = data
self.__count = 0 def __iter__(self):
print("call iterator __iter__().")
return self def __next__(self):
print("call iterator __next__().")
if self.__count < len(self.__data):
val = self.__data[self.__count]
self.__count += 1
return val
else:
raise StopIteration
为了知道python何时调用__iter__()方法,我添加了一个printf函数来做标记。 现在把这两个类导入到当前空间中: Python In [1]: from list_iter import * In [2]: a = ListIterable([1,2,4,5,6]) In [3]: b = a.__iter__()
call iterables __iter__(). In [4]: a
Out[4]: <list_iter.ListIterable at 0x39446d0> In [5]: b
Out[5]: <list_iter.ListIterator at 0x39447b0>
In [1]: from list_iter import * In [2]: a = ListIterable([1,2,4,5,6]) In [3]: b = a.__iter__()
call iterables __iter__(). In [4]: a
Out[4]: <list_iter.ListIterable at 0x39446d0> In [5]: b
Out[5]: <list_iter.ListIterator at 0x39447b0> In [6]:
可见a是iterable对象(实现了__iter__()),b是iterator对象(实现了__next__())。 下面看看这样做是不是就可以重复多次迭代了: Python In [6]: [i for i in a]
call iterable __iter__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
Out[6]: [1, 2, 4, 5, 6] In [7]: [i for i in a]
call iterable __iter__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
Out[7]: [1, 2, 4, 5, 6] In [6]: [i for i in a]
call iterable __iter__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
Out[6]: [1, 2, 4, 5, 6] In [7]: [i for i in a]
call iterable __iter__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
call iterator __next__().
Out[7]: [1, 2, 4, 5, 6] In [8]:
重复迭代是可以了,从输出中我们可以看出一些什么来 我们在使用迭代工具对iterable对象进行迭代的时候首先调用的是iterable的__iter__()方法,返回一个迭代器对象,也就是ListIterator的实例。
然后再遍历的时候是调用iterator的next方法输出值。
这样就可以解释了为什么这样处理能够多次迭代了,因为每次使用迭代工具迭代的时候都会调用__iter__()返回一个新的迭代器对象,这样就相当于创建多个迭代器了,自然可以看起来是重复迭代了!
可变对象和迭代器 在迭代可变对象时候,一个序列的迭代器只是记录当前到达了序列中的第几个元素,所以如果在迭代过程中改变了序列的元素。更新会立即反应到所迭代的条目上。
我写了个测试看了下,的确: Python In [13]: c = [1,2,3,4,5] In [14]: d = iter(c) In [15]: for i in c:
....: print(i)
....: c.remove(i)
....: In [13]: c = [1,2,3,4,5] In [14]: d = iter(c) In [15]: for i in c:
....: print(i)
....: c.remove(i)
....: 可见上面边迭代边删除列表的元素,但是最后却只输出了1, 3, 5,这是为啥?
既然迭代器只记得是在列表中第几个元素,那么当在第0个元素的时候将会输出1然后删除1,这是列表变成了 Python [2, 3, 4, 5]
1
[2, 3, 4, 5]
但是迭代器记得我是在第二个位置上面,就指向了列表中的第二个位置上,也就是3,然后输出3.
以此类推,最后只能输出1,3,5了。
如果我猜测的没错的话,剩余的列表应该只剩下2和4了: Python In [17]: c
Out[17]: [2, 4]
1
2
In [17]: c
Out[17]: [2, 4]

python 迭代器(转)的更多相关文章

  1. Python迭代器,可迭代对象,生成器

    迭代器 迭代器(iterator)有时又称游标(cursor)是程式设计的软件设计模式,可在容器物件(container,例如链表或阵列)上遍访的界面,设计人员无需关心容器物件的内存分配的实现细节. ...

  2. python迭代器与iter()函数实例教程

    python迭代器与iter()函数实例教程 发布时间:2014-07-16编辑:脚本学堂 本文介绍了python迭代器与iter()函数的用法,Python 的迭代无缝地支持序列对象,而且它还允许程 ...

  3. Python 迭代器和列表解析

    Python 迭代器和列表解析 1)迭代器 一种特殊的数据结构,以对象形式存在 >>> i1 = l1.__iter__() >>> i1 = iter(l1) 可 ...

  4. Python迭代器,生成器--精华中的精华

    1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...

  5. Python 迭代器和生成器(转)

    Python 迭代器和生成器 在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的, ...

  6. 一文搞懂Python迭代器和生成器

    很多童鞋搞不懂python迭代器和生成器到底是什么?它们之间又有什么样的关系? 这篇文章就是要用最简单的方式让你理解Python迭代器和生成器! 1.迭代器和迭代过程 维基百科解释道: 在Python ...

  7. Python - 迭代器与生成器 - 第十三天

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

  8. python迭代器,生成器

    1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...

  9. 怎么理解Python迭代器与生成器?

    怎么理解Python迭代器与生成器?在Python中,使用for ... in ... 可以对list.tuple.set和dict数据类型进行迭代,可以把所有数据都过滤出来.如下:         ...

  10. Python迭代器生成器与生成式

    Python迭代器生成器与生成式 什么是迭代 迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭 ...

随机推荐

  1. Python 疑难问题:[] 与 list() 哪个快?为什么快?快多少呢?

    本文出自"Python为什么"系列,请查看全部文章 在日常使用 Python 时,我们经常需要创建一个列表,相信大家都很熟练了吧? # 方法一:使用成对的方括号语法 list_a ...

  2. 多测师讲解接口测试 —jmeter接数据库(004)_高级讲师肖sir

    1.连接数据库jar包 2. 3. jdbc:mysql://192.168.153.131:3306/baoan?zeroDateTimeBehavior=convertToNull&all ...

  3. 编程语言那么多,为什么偏偏是C语言成了大学的必修课?

    谁叫你不幸生在中国了?--何祚庥(中国科学院院士) 这是一本给非计算机专业的大学生的C语言的书."我不是学计算机的,为啥要学C语言?"这个问题每年在中华大地都会被问上几百万次. 被 ...

  4. 【图论】HDU 5961 传递

    题目内容 题目链接 我们称一个有向图G是传递的当且仅当对任意三个不同的顶点a,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c. 我们称图G是一个竞赛图,当且仅当它是一个有向图 ...

  5. monolog handler用哪个

    Handlers 记录日志到文件与系统日志(syslog) StreamHandler:记录日志到任何 PHP stream,用它来记录到文件. RotatingFileHandler: 每天一个文件 ...

  6. Jmeter入门(3)- Jmeter录制脚本

    一. 录制web端 1. Badboy的介绍和安装 1.1 使用第三方工具Badboy来录制. 免费的web自动化测试工具 一个浏览器模拟工具 主要进行脚本的录制和回访,和对录制脚本进行调试,可以将脚 ...

  7. JS的各种数据类型

    Number js与其他编程不一样,不管是整数还是浮点,都称为数字类型(Number) 例:123,1.11111,-960 当该类型结果不存在时,即表示为 NaN (Not a Number) In ...

  8. 支持向量机SVM基本问题

    1.SVM的原理是什么? SVM是一种二类分类模型.它的基本模型是在特征空间中寻找间隔最大化的分离超平面的线性分类器.(间隔最大是它有别于感知机) 试图寻找一个超平面来对样本分割,把样本中的正例和反例 ...

  9. 【2】TensorFlow光速入门-数据预处理(得到数据集)

    本文地址:https://www.cnblogs.com/tujia/p/13862351.html 系列文章: [0]TensorFlow光速入门-序 [1]TensorFlow光速入门-tenso ...

  10. mysql自动化建表脚本

    主脚本 配置文件 执行结果 主脚本内容 由于在awk中用常规方法无法转译单引号,所以用了单引号的八进制编码进行转译代替\047 等价于 ' [root@hadoop01 data]# cat crea ...