使用 x = [1,2,3,4]
,我可以从 i = iter(x)
获取迭代器。
有了这个迭代器,我可以使用 zip 函数创建一个包含两个项目的元组。
>>> i = iter(x)
>>> zip(i,i)
[(1, 2), (3, 4)]
即使我可以使用这种语法来获得相同的结果。
>>> zip(*[i] * 2)
[(1, 2), (3, 4)]
这是如何运作的?带有 zip(i,i)
和 zip(*[i] * 2)
的迭代器如何工作?
最佳答案
迭代器就像一个项目流。您一次只能查看流中的一个项目,并且您只能访问第一个元素。要查看流中的某些内容,您需要将其从流中移除,一旦您从流的顶部取出某些内容,它就会永远从流中消失。
当您调用 zip(i, i)
时,zip
首先查看第一个流并取出一个项目。然后它查看第二个流(恰好与第一个流相同的流)并取出一个项目。然后它从这两个项目中生成一个元组并一遍又一遍地重复这个过程,直到流中没有任何东西为止。
如果我用纯 python 编写 zip
函数(为简单起见,只有 2 个参数),也许会更容易看出。它看起来像1:
def zip(a, b):
out = []
try:
while True:
item1 = next(a)
item2 = next(b)
out.append((item1, item2))
except StopIteration:
return out
现在想象一下您正在讨论 a
和 b
是同一个对象 的情况。在这种情况下,我们只需在迭代器上调用 next
两次(在您的示例中为 i
),它只会从 i
中获取前两项按顺序将它们打包成一个元组。
一旦我们理解了为什么 zip(i, i)
的行为方式,zip(*([i] * 2))
就不太一样了难的。让我们从内到外阅读表达式...
[i] * 2
这只是创建了一个新列表(长度为 2),其中两个元素都是对迭代器 i
的引用。所以它和 zip(*[i, i])
是一样的(只是当你想重复某件事超过 2 次时写起来更方便)。 *
解包是 python 中的常见习惯用法,您可以在 the python tutorial 中找到更多信息。 .它的要点是 python 获取可迭代对象并将其“解包”,就好像可迭代对象的每个项目都是函数的一个单独的位置参数。所以:
zip(*[i, i])
做同样的事情:
zip(i, i)
现在 Bob 是我们的叔叔了。我们刚刚绕了一圈,因为 zip(i, i)
是讨论的起点。
1这个示例代码肯定比前面提到的只接受 2 个参数更简单。例如,zip
可能会在输入参数上调用 iter
以便它适用于任何可迭代对象(不仅仅是迭代器),但这应该足以说明问题跨越...
关于Python 迭代器和 zip,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38024554/