我目前正在阅读Python 3.5的官方文档。
它声明range()
是可迭代的,list()
和for
是迭代器。 [section 4.3]
然而,here它表明zip()
构成了一个迭代器。
我的问题是,当我们使用这条指令时:
list(zip(list1, list2))
我们使用迭代器(list()
)迭代另一个迭代器吗?
答案 0 :(得分:3)
通过重复使用术语“迭代器”,文档在这里引起了一些混淆。
iterator protocol有三个组成部分:
Iterables;你可以潜在地迭代并逐个获取其元素的东西。
迭代;做迭代的事情。每当您想要遍历迭代的所有项目时,您需要其中一项来跟踪您在过程中的位置。这些不可重复使用;一旦你到达终点,就是这样。对于大多数迭代,您可以创建多个独立迭代器,每个迭代迭代器独立跟踪位置。
迭代器的消费者;那些想要对这些物品做些什么的事情。
for
循环是后者的一个例子,所以#3。 for
循环使用iter()
function为您想要循环的任何内容生成迭代器(上面的#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)。如果将另一个iterable(#1)传递给list()
调用,则会生成一个包含该iterable中所有元素的列表对象。但列表对象本身也是可迭代的。
zip()
接受多个迭代(#1),它本身就是一个迭代器(#2)。 zip()
为你给它的每个迭代存储一个新的迭代器(#2)。每次你向zip()
询问下一个元素时,zip()
都会使用每个包含的iterables中的下一个元素构建一个新元组:
>>> 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()
电话。
答案 1 :(得分:1)
文档措辞严厉。以下是您所指的部分:
我们说这样的对象是 iterable ,也就是说,适合作为函数和构造的目标,这些函数和构造期望在供应耗尽之前可以获得连续项目的东西。我们已经看到
for
语句是一个迭代器。函数list()
是另一个函数;它从迭代创建列表:
在本段中, iterator 不是指Python迭代器对象,而是“迭代某些东西”的一般概念。特别是,for
语句不能是迭代器对象,因为它根本不是对象;它是一种语言结构。
回答您的具体问题:
......当我们使用这条指令时:
list(zip(list1, list2))
我们使用迭代器(
list()
)迭代另一个迭代器吗?
不,list()
不是迭代器。它是list
类型的构造函数。它可以接受任何可迭代(包括迭代器)作为参数,并使用该iterable构造列表。
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
已经用尽了。