【问题标题】:Python iterator and zipPython 迭代器和 zip
【发布时间】:2016-10-27 17:33:53
【问题描述】:

使用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) 的迭代器如何工作?

【问题讨论】:

  • [i] * 2 == [i, i] / func(*[i, i]) == func(i, i)

标签: python iterator zip


【解决方案1】:

迭代器就像一个项目流。您一次只能查看一个流中的项目,并且您只能访问第一个元素。要查看流中的某些内容,您需要将其从流中移除,一旦您从流顶部取出某些内容,它就会从流中永久消失。

当您调用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

现在想象一下您所讨论的情况,ab 是同一个对象。在这种情况下,我们只需在迭代器上调用next 两次(在您的示例中为i),它将按顺序从i 中获取前两项并将它们打包成一个元组。

一旦我们了解了 zip(i, i) 的行为方式为何,zip(*([i] * 2)) 就不会太难了。让我们从内到外阅读表达式...

[i] * 2

这只是创建了一个新列表(长度为 2),其中两个元素都是对迭代器 i 的引用。所以它和zip(*[i, i]) 是一样的(当你想重复超过2次的时候写起来更方便)。 * unpacking 是 python 中的常用习语,您可以在 the python tutorial 中找到更多信息。它的要点是 python 获取可迭代对象并“解包”它,就好像可迭代对象的每个项目都是函数的单独位置参数一样。所以:

zip(*[i, i])

做同样的事情:

zip(i, i)

现在鲍勃是我们的叔叔了。自从zip(i, i) 是本次讨论的起点,我们才刚刚开始讨论。

1这个示例代码绝对比前面提到的只接受 2 个参数更简单。例如,zip 可能会在输入参数上调用iter,以便它适用于任何可迭代(不仅仅是迭代器),但这应该足以说明问题......

【解决方案2】:

每次从迭代器中获取项目时,它都会停留在该位置而不是“倒带”。所以zip(i, i)i 获取第一项,然后从i 获取第二项,并将其作为tuple 返回。它继续为每个可用对执行此操作,直到迭代器耗尽。

zip(*[i]*2) 通过将i 乘以2 创建[i, i]list,然后用最左边的* 解包,实际上发送两个参数iizip,产生与第一个 sn-p 相同的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 2021-06-19
    • 2015-04-08
    • 2014-11-25
    • 2019-06-03
    相关资源
    最近更新 更多