迭代器协议 及 python中强大的for循环机制
一、什么是迭代器协议
迭代器协议:是指,对象必须提供一个__next__()方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。(只能往后走,不能往前退) 协议:是一种约定。可迭代对象实现了迭代器协议,python的内部工具,如for循环、sum函数、min函数、max函数等都是遵循迭代器协议访问对象。 可迭代对象:实现了迭代器协议的对象。(如何实现?对象内部定义了一个__iter__()方法)
二、python中强大的for循环机制
1、for循环的本质是什么?
for循环的本质,其实就是遵循迭代器协议去访问对象。然后在for循环的时候去调用 可迭代对象 内部的__next__()方法。
那么,列表、元组、字符串、字典、集合、文件对象是不是可迭代对象呢?答案是:否。
他们只不过是在for循环时,调用了他们内部的__iter__()方法,把他们变成了可迭代对象。
然后for循环,再调用可迭代对象内部的__next__()方法去取值,而且for循环会捕捉StopIteration异常,以终止迭代。
L = [1, 2, 3, 4, 5]
for i in L:
print(i)
具体步骤解析如下:
(1)查看列表的内置方法:
L = [1, 2, 3, 4, 5]
print(dir(L))
输出结果:(可看出,是没有__next__()方法的,所以不是可迭代对象)
['__add__', '__class__', '__contains__', '__delattr__',
'__delitem__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__',
'__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__len__',
'__lt__', '__mul__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__reversed__', '__rmul__',
'__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'append', 'clear', 'copy', 'count',
'extend', 'index', 'insert', 'pop', 'remove', 'reverse',
'sort']
(2)调用了他们内部的__iter__()方法:
L = [1, 2, 3, 4, 5]
iter_test = L.__iter__()
print(iter_test)
输出的结果:(把列表变为可迭代对象)
<list_iterator object at 0x000001FC55F71788>
(3)此时再去调用可迭代对象的__next__()方法,就可以一个个取出值,调用一次取一个。
L = [1, 2, 3, 4, 5]
iter_test = L.__iter__()
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
输出结果:
2、为什么要用for循环?
我们都知道,还有一种方法可以去循环遍历取值,那就是使用下标的方式去访问。但是只有序列类型对象,如字符串、列表、元组 才支持使用下标的方式去取值。
L = [1, 2, 3, 4, 5]
index = 0
while index < len(L):
print(L[index])
index += 1
而集合、字典、文件对象,这样的非序列类型对象,是不支持使用下标的方式去访问的。
所以,for循环就基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即,在遍历之前,先调用对象的__iter__()方法,把对象变成了可迭代对象(迭代器),然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来访问了。
dic = {1, 2, 3}
dic_test = dic.__iter__()
while True:
try:
print(dic_test.__next__())
except StopIteration:
print("迭代完毕,循环截止了!")
break
|