迭代器是一种可以被遍历的对象,并且能够作用于next()函数,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往后遍历,不能回溯。不像列表,你随时可以取后面的数据,也可以返回头取前面的数据,迭代器通常要实现两个基本方法next()和iter()。
概括的说,一个对象实现了__iter__()和__next__()方法,那么它就是一个迭代器对象。
但是只实现了__iter__()方法没有实现__next__()方法,就只是一个可迭代对象。
例如:
# 3.6之前的版本是不需要带.abc的,3.7就会提示需要加.abcfrom collections.abc import Iterable, Iteratorclass IterA: def __iter__(self): # 我们这里返回一个列表 return [1, 2, 3]class IterB: passiterA = IterA()iterB = IterB()# 可以看到iterA 是一个可迭代对象# iterB 是一个不可迭代对象print(isinstance(iterA, Iterable)) # Trueprint(isinstance(iterB, Iterable)) # False# iterA是一个可迭代对象,但并不是一个迭代器对象# 因为IterA类中并没有实现next方法print(isinstance(iterA, Iterator)) # False我们在IterA类中实现__next__()方法,IterA类就变成了一个迭代器对象了。
# 3.6之前的版本是不需要带.abc的,3.7就会提示需要加.abcfrom collections.abc import Iterable, Iteratorclass IterA: def __iter__(self): # 我们这里返回一个列表 return [1, 2, 3] def __next__(self): passiterA = IterA()# 可以看到iterA 是一个可迭代对象# iterB 是一个不可迭代对象print(isinstance(iterA, Iterable)) # True# iterA对象也是要给迭代器对象print(isinstance(iterA, Iterator)) # True"""1.迭代器的应用场景 1).如果数列的数据规模巨大 2).数列有规律,但是依靠列表推导式描述不出来 2.数学中有个著名的斐波那契数列(Fibonacci),数列中第?个数0,第?个数1,其后的每?个数都可由前两个数相加得到:如下:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...现在我们想要通过for...in...循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以?迭代器来实现,每次迭代都通过数学计算来?成下?个数。"""from collections.abc import Iterable, Iteratorclass FibIterator(object): """ fib数列迭代器 """ # 初始化方法 def __init__(self, count): # 斐波拉契数列中的前两个数 self.num1 = 0 self.num2 = 1 # 用来保存迭代的总次数 self.count = count # 用来记录迭代次数(计数器) self.i = 0 # 实现__iter__表示FibIterator是一个可迭代对象 # 返回对象自己。是一个可迭代对象 def __iter__(self): return self # 实现__next__方法,是FibIterator定义为迭代器对象的重要条件之一 def __next__(self): # 判断是否迭代结束,如果没有到达迭代次数,则返回数据 # self.count 需要迭代的次数 # self.i已迭代次数 if self.i < self.count: item = self.num1 # 计算num1, num2的值,方便下次迭代返回 # 这里运用的是序列的封包与解包,不会的可以看我以前的文章(元组) self.num1, self.num2 = self.num2, self.num1 + self.num2 # 执行一次next方法,计数器+1 self.i += 1 # 返回新获得的数, # 也就是前两个数求和的第三个数 return item else: # 到达了迭代次数,抛出异常 raise StopIteration# 创建一个fib数列迭代器对象fibIter = FibIterator(15)# fibIter对象是一个迭代器print(isinstance(fibIter, Iterable)) # Trueprint(isinstance(fibIter, Iterator)) # True# 转换为列表查看fib对象内容# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]print(list(fibIter))# 遍历,可执行for li in fibIter: print(li)(1)整理总结
__iter__方法,如果实现了,该对象就是一个可迭代对象。__iter__()和__next__()方法,那么它就是一个迭代器对象。iter()函数把可迭代对象(Iterable)变成迭代器对象(Iterator)。isinstance()函数,可以判断一个对象是否是Iterable对象或者是Iterator对象。print(isinstance(fibIter, Iterable)) print(isinstance(fibIter, Iterator)) (2)迭代协议
当任何可迭代对象传入到for循环或其他迭代工具中进行遍历时,迭代工具都是先通过iter()函数获得与可迭代对象对应的迭代器,然后再对迭代器调用next()函数,不断的依次获取元素,并在捕捉到StopIteration异常时,确定完成迭代,这就是完整的迭代过程,这也称之为“迭代协议”。
(3)为什么任何Python序列都可迭代?
__getitem__方法__iter__方法__getitem__方法,而且其参数是从0开始的索引,这种对象也可迭代,但它不是一个可迭代对象。__iter__方法,但实现了__getitem__方法,__getitem__()方法可以通过iter()函数转成Iterator,即可以在for循环中使用,按顺序(从0开始)获取元素。from collections.abc import Iterable, Iteratorclass IterObj: def __init__(self): self.a = [3, 5, 7, 11, 13, 17, 19] def __getitem__(self, i): return self.a[i]# 从创建对象it = IterObj()print(isinstance(it, Iterable)) # falseprint(isinstance(it, Iterator)) # false# <__main__.IterObj object at 0x0000000002573AC8>print(it)# # <iterator object at 0x10b231278>print(iter(it))# 遍历for i in it: print(i)归纳:
- 如果这个可迭代对象要在
for循环中被使用,那么它就应该能够被内置的iter()函数调用并转化成Iterator对象。- Python的for语法功能非常强大,可以遍历任何可迭代的对象。
参考:
- https://blog.csdn.net/xun527/article/details/76696241
- https://www.cnblogs.com/angrycode/p/11386970.html
- https://zhuanlan.zhihu.com/p/69557317