Python学习之路(14)——迭代器
在Python中,有以下对象可以通过for语句来直接遍历:
一类是集合数据类型,如list、tuple、dict、set和str等;
一类是generator,包括生成器和带yield的generator function。
这些对象都可以被称为可迭代对象(Iterable)。
迭代器
迭代器对象要求支持迭代器协议的对象,在Python中,支持迭代器协议就是实现对象的iter()和next()方法。
这两个方法是迭代器最基本的方法,前者用来获得迭代器对象,后者用来获取容器中的下一个元素,并在结尾时引发StopIteration异常。
因此,我们将可以被next()函数调用并不断返回下一个值的对象成为迭代器:Iterator。
示例:
>>> str1 = 'I love you' >>> it = iter(str1) >>> it <str_iterator object at 0x0000000003563080> >>> next(it) 'I' >>> next(it) ' ' >>> next(it) 'l' >>>
list、dict、str等数据类型是否是迭代器呢?
>>> from collections import Iterator
>>> isinstance([1, 2, 3], Iterator)
False
>>> isinstance({1: 'one'}, Iterator)
False
>>> isinstance('hello', Iterator)
False
>>>
>>> isinstance(iter([1, 2, 3]), Iterator)
True
>>>
可以看出list、dict等数据类型不是迭代器,而iter()函数可以把一个对象转换成迭代器Iterator。
因为Python的Iterator对象标识的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,指导没有数据时抛出StopIteration异常。可以把这个数据流看做一个有序序列,但我们却不能提前知道序列的长度,只能通过不断next()函数实现按需计算下一个数据,所有Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结:
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型。
实际上Python的for循环就是不断调用next()函数实现的,如:
>>> for x in list(range(5)): pass >>>
实际上完全等价于:
>>> it = iter(list(range(5))) >>> while True: try: x = next(it) except StopIteration: break >>>
迭代器的魔法方法__iter__()和__next__()
__iter__():该方法返回的是迭代器本身,实际上就是return self
__next__():该方法控制迭代器的迭代规则
下面以斐波那契数列为例:
>>> class Fibs:
def __init__(self, n = 100):
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n:
raise StopIterator
return self.a
>>> fibs = Fibs()
>>> for each in fibs:
print(each, end = ' ')
1 1 2 3 5 8 13 21 34 55 89 Traceback (most recent call last):
File "<pyshell#72>", line 1, in <module>
for each in fibs:
File "<pyshell#68>", line 11, in __next__
raise StopIterator
NameError: name 'StopIterator' is not defined
>>> fibs = Fibs(500)
>>> for each in fibs:
print(each, end = ' ')
1 1 2 3 5 8 13 21 34 55 89 144 233 377 Traceback (most recent call last):
File "<pyshell#76>", line 1, in <module>
for each in fibs:
File "<pyshell#68>", line 11, in __next__
raise StopIterator
NameError: name 'StopIterator' is not defined
>>>
浙公网安备 33010602011771号