虽然n 被称为循环变量,但列表绝对不是迭代器。它是可迭代对象,即 iterable,但它不是 iterator。可迭代对象本身可能是迭代器,但并非总是如此。也就是说,迭代器是可迭代的,但并不是所有的可迭代器都是迭代器。在list 的情况下,它只是一个可迭代的。
它是一个可迭代的,因为它实现了一个__iter__ 方法,该方法返回一个迭代器:
从Python Glossary一个可迭代是:
一个能够一次返回其成员的对象。示例
可迭代对象包括所有序列类型(例如 list、str 和 tuple)
以及一些非序列类型,如字典、文件对象和
您使用__iter__() 或__getitem__() 方法定义的任何类。
Iterables 可用于 for 循环和许多其他地方
需要序列(zip(),map(),...)。 当一个可迭代对象是
作为参数传递给内置函数iter(),它返回一个
对象的迭代器。此迭代器适用于一次通过
一组值。使用可迭代对象时,通常不需要
调用 iter() 或自己处理迭代器对象。 for 语句
自动为您执行此操作,创建一个临时的未命名变量
在循环期间保持迭代器。
所以,观察:
>>> x = [1,2,3]
>>> iterator = iter(x)
>>> type(iterator)
<class 'list_iterator'>
>>> next(iterator)
1
>>> next(iterator)
2
>>> next(iterator)
3
>>> next(iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
理解 Python 中的 for 循环如下所示:
for n in some_iterable:
# do something
相当于:
iterator = iter(some_iterable)
while True:
try:
n = next(iterator)
# do something
except StopIteration as e:
break
通过调用对象的__iter__ 方法返回的迭代器也实现__iter__ 方法(通常返回自身),但它们也实现__next__ 方法。因此,检查某事物是否可迭代的一种简单方法是查看它是否实现了 next 方法
>>> next(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
同样,从Python Glossary,迭代器是:
表示数据流的对象。反复调用
迭代器的__next__() 方法(或将其传递给内置函数
next()) 返回流中的连续项目。当没有更多数据时
而是引发了一个 StopIteration 异常。在此刻,
迭代器对象已用尽并且对其的任何进一步调用
__next__() 方法只是再次引发 StopIteration。 迭代器必须有一个返回迭代器对象的__iter__() 方法
本身,所以每个迭代器也是可迭代的,并且可以在大多数情况下使用
接受其他迭代的地方。一个值得注意的例外是
尝试多次迭代的代码。容器对象
(例如列表)每次传递时都会产生一个新的迭代器
到 iter() 函数或在 for 循环中使用它。尝试这个
迭代器将只返回使用的相同耗尽的迭代器对象
在之前的迭代过程中,使它看起来像一个空的
容器。
我已经用上面的next 函数说明了迭代器的行为,所以现在我想专注于粗体部分。
基本上,可以使用迭代器代替可迭代对象,因为迭代器始终是可迭代的。但是,迭代器仅适用于单次传递。因此,如果我使用非迭代器可迭代对象,例如列表,我可以执行以下操作:
>>> my_list = ['a','b','c']
>>> for c in my_list:
... print(c)
...
a
b
c
还有这个:
>>> for c1 in my_list:
... for c2 in my_list:
... print(c1,c2)
...
a a
a b
a c
b a
b b
b c
c a
c b
c c
>>>
迭代器的行为方式几乎相同,所以我仍然可以这样做:
>>> it = iter(my_list)
>>> for c in it:
... print(c)
...
a
b
c
>>>
但是,迭代器不支持多次迭代(好吧,你可以让你的迭代器支持,但通常它们不支持):
>>> it = iter(my_list)
>>> for c1 in it:
... for c2 in it:
... print(c1,c2)
...
a b
a c
这是为什么呢?好吧,回想一下 for 循环在底层使用的迭代器协议发生了什么,并考虑以下几点:
>>> my_list = ['a','b','c','d','e','f','g']
>>> iterator = iter(my_list)
>>> iterator_of_iterator = iter(iterator)
>>> next(iterator)
'a'
>>> next(iterator)
'b'
>>> next(iterator_of_iterator)
'c'
>>> next(iterator_of_iterator)
'd'
>>> next(iterator)
'e'
>>> next(iterator_of_iterator)
'f'
>>> next(iterator)
'g'
>>> next(iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> next(iterator_of_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
当我在迭代器上使用iter() 时,它返回了自己!
>>> id(iterator)
139788446566216
>>> id(iterator_of_iterator)
139788446566216