文档在这里造成了一些混淆,因为它重新使用了“iterator”一词。
迭代器协议有三个组成部分:可迭代对象、迭代器和消费者。
可迭代对象:您可以逐个获取其元素的事物。
迭代器:用于迭代的事物。每次想要遍历可迭代对象中所有项目时,都需要一个迭代器来跟踪您在过程中的位置。这些不可重复使用;一旦到达末尾,就是这样。对于大多数可迭代对象,您可以创建多个独立的迭代器,每个迭代器都可以单独跟踪位置。
迭代器的使用者:那些想要对项目执行操作的事物。
循环语句for
是第3种情况的例子。循环语句for
使用iter()
函数为您要循环的任何内容生成一个迭代器(上面的#2),因此“任何内容”必须是可迭代对象(上面的#1)。
range()
是第1种情况的例子;它是可迭代对象。您可以多次独立地迭代它。
>>> r = range(5)
>>> r_iter_1 = iter(r)
>>> next(r_iter_1)
0
>>> next(r_iter_1)
1
>>> r_iter_2 = iter(r)
>>> next(r_iter_2)
0
>>> next(r_iter_1)
2
r_iter_1
和r_iter_2
是两个不同的迭代器,每次请求下一个元素时,它们都会根据自己的内部记录提供答案。
list()
是同时作为可迭代对象(#1)和迭代消费者(#3)的一个示例。如果你向list()
传递另一个可迭代对象(#1),那么将生成包含该可迭代对象中所有元素的列表对象。但是列表对象本身也是可迭代的。zip()
接受多个可迭代对象(#1),并且它本身是一个迭代器(#2)。zip()
会为你提供的每个可迭代对象存储一个新的迭代器(#2)。每次询问zip()
下一项时,它都会使用来自每个包含的可迭代对象的下一个元素构建一个新元组:>>> lst1, lst2 = ['foo', 'bar'], [42, 81]
>>> zipit = zip(lst1, lst2)
>>> next(zipit)
('foo', 42)
>>> next(zipit)
('bar', 81)
最终,list(zip(list1, list2))
使用了 list1
和 list2
作为可迭代对象 (#1),zip()
消耗了这些对象 (#3),当它自己被外部的 list()
调用消耗时。
range()
不被认为是一个iterator
而是iterable
呢?它难道不是像zip()
一样工作的吗? - Ammar Alyousfifor
语句是这样一个迭代器。函数list()
也是一个迭代器;它从可迭代对象创建列表。for
语句不能是迭代器对象,因为它根本不是对象,而是一种语言结构。... when we use this instruction:
list(zip(list1, list2))
are we using an iterator (
list()
) to iterate through another iterator?
不,list()
不是迭代器。它是 list
类型的构造函数。它可以接受任何可迭代对象(包括迭代器)作为参数,并使用该可迭代对象构造一个列表。
zip()
是一个迭代器函数,即返回迭代器的函数。在您的示例中,它返回的迭代器被传递给 list()
,后者从中构造了一个 list
对象。
判断一个对象是否为迭代器的简单方法是使用 next()
函数调用它,并观察发生了什么:
>>> list1 = [1, 2, 3]
>>> list2 = [4, 5, 6]
>>> zipped = zip(list1, list2)
>>> zipped
<zip object at 0x7f27d9899688>
>>> next(zipped)
(1, 4)
zipped
的下一个元素。>>> list3 = list(zipped)
>>> list3
[(2, 5), (3, 6)]
list3
中,因为我们已经使用next()
消耗了第一个元素。>>> next(list3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
>>> next(zipped)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
这一次,尽管 zipped
是一个迭代器,但是调用 next()
会引发 StopIteration
错误,因为它已经被用完来构建 list3
。
for
不是一个迭代器。range()
是一个序列,就像list
一样,两者都是可迭代的。你需要为可迭代对象创建一个新的迭代器来进行实际的迭代。 - Martijn Pieters