【Python那些事儿】Python中的迭代器
主要记录:迭代器(iterator)协议对象必须提供一个next()方法,执行该方法时,要么返回迭代中的下一项,要么引起一个StopIteration异常。只能往前访问,不会后退。在Python中,支持迭代器协议就是实现对象的__iter__和next()方法。__iter__方法:返回迭代器对象本身;next()方法:返回容器中的下一个元素,在结尾时引发StopIteration异常终
·
迭代器(iterator)协议
- 对象必须提供一个next()方法,执行该方法时,要么返回迭代中的下一项,要么引起一个StopIteration异常。
- 只能往前访问,不会后退。
- 在Python中,支持迭代器协议就是实现对象的
__iter__
和__next__()
方法。
__iter__()
方法:返回迭代器对象本身;__next__()
方法:返回容器中的下一个元素,在结尾时引发StopIteration异常终止迭代器。
可迭代对象(iterable)
- 实现了迭代器协议的对象,就是可迭代对象。
- 如何实现迭代器协议:对象内部定义了一个
__iter__()
方法。 - 在Python中,list、tuple、dict、set以及生成器对象都是可迭代对象。如果不确定哪个可迭代,可以使用内置函数
iter()
测试。
>>> iter([6,8,10])#返回listterator对象
<listiterator object at 0x7f992a891210>
>>> iter({'a':1,'b':2})#返回dictionary-keyiterator对象
<dictionary-keyiterator object at 0x7f992a880838>
>>> iter(666)#不是可迭代对象
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
- 所有的iterable均可以通过内置函数
iter()
转化为iterator。
迭代器
- 迭代器对象从集合的第一个元素开始访问,直到所有元素被访问完结束,迭代器只能往前不能后退。
- 迭代器有两个基本方法:iter、text方法。
- 内置函数
iter()
、next()
,本质上都是用的对象的__iter__()
、__next__()
的方法。
- 内置函数
迭代器优点
- 对于支持随机访问的数据结构:list、tuple等,迭代器和经典的for循环(索引访问)相比,并无优势,反而失去了索引值。不过可以使用内置函数
enumerate()
找回这个索引值。但对于无法随机访问的数据结构:set()
,迭代器是唯一的访问元素的方式。 - 省内存:迭代器不需要事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或销毁。这也是迭代器的一大优点:适合用于遍历一个巨大的或无限的集合,比如几个G的文件。下面用斐波那契数列为例:
- 代码一直接在
fab(max)
中用print打印会导致函数的可复用性变差,因此fab返回None。其他函数无法获得fab函数返回的数列; - 代码二满足了可复用性的需求,但是占用了内存空间;
- 代码三Fabs类通过
next()
不断返回数列的下一个,内存占用始终为常数。
- 代码一直接在
#代码一:
def fab(max):
L = []
n, a, b = 0, 0, 1
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
#代码二:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1
#代码三:
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
使用迭代器
- 使用内置函数iter(iterable)获取迭代器对象:
>>> iter(range(5))
<listiterator object at 0x7f992a8911d0>
>>> iter(xrange(5))
<rangeiterator object at 0x7f992a892240>
- 使用
next()
方法访问下一个元素:
>>> a.next()
0
>>> a.next()
1
>>> a.next()
2
>>> a.next()
3
- 迭代器越界会抛出StopIteration异常:
>>> a.next()
4
>>> a.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
处理方法:
lst = range(5)
it = iter(lst)
try:
while True:
val = it.next()
print val
except StopIteration:
pass
#输出
0
1
2
3
4
注意:Python专门为for关键字做了迭代器的语法糖:在for循环中,Python将自动调用内置函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。
自定义迭代器
下面例子中实现了一个MyRange的类型,这个类型中实现了__iter__()
方法,通过这个方法返回对象本身作为迭代器对象;同时,实现了next()
方法用来获取容器中的下一个元素,当没有可访问元素后,就抛出StopIteration异常。
class MyRange(object):
def __init__(self, n):
self.idx = 0
self.n = n
def __iter__(self):
return self
def next(self):
if self.idx < self.n:
val = self.idx
self.idx += 1
return val
else:
raise StopIteration()
myRange = MyRange(5)
for i in myRange:
print i
#输出:
0
1
2
3
4
更多推荐
已为社区贡献2条内容
所有评论(0)