理解zip函数

14 投票
2 回答
18358 浏览
提问于 2025-04-16 05:02

大家讨论的都是 Python 3.1.2 版本;你可以查看 Python 文档 来了解我问题的来源。

我知道 zip 是干什么的,但我不明白为什么它可以这样实现:

def zip(*iterables):
    # zip('ABCD', 'xy') --> Ax By
    iterables = map(iter, iterables)
    while iterables:
        yield tuple(map(next, iterables))

假设我调用 zip(c1, c2, c3)。如果我理解得没错,最开始的 iterables 是一个包含 (c1, c2, c3) 的元组。

这行代码 iterables = map(iter, iterables) 把它转换成一个迭代器,这个迭代器如果被遍历的话,会依次返回 iter(c1)iter(c2)iter(c3)

在循环内部,map(next, iterables) 是一个迭代器,如果遍历它,会返回 next(iter(c1))next(iter(c2))next(iter(c3))。然后 tuple 这个调用会把它转换成 (next(iter(c1)), next(iter(c2)), next(iter(c3)),而且在第一次调用的时候就把它的参数(iterables)用完了。至于我能理解的,我不明白为什么 while 循环还能继续,因为它是检查 iterables;如果它继续的话,为什么 tuple 的调用不会返回一个空元组(因为迭代器已经用完了)。

我肯定是漏掉了什么很简单的东西……

2 个回答

7

看起来这段代码是为python-2.x版本写的。在python 3.x中,它甚至都无法正常运行。

在python-2.x中,map会返回一个迭代器的列表,当你调用next时,它会返回迭代器中的一个元素,这些元素会组合成一个元组。所以,假设有

>>> zip('ABCD', 'xy')

iterables是一个包含两个迭代器的列表,在while循环的每次迭代中,都会消耗迭代器中的第一个剩余元素(比如''A''x'等),并将其作为元组的一个元素返回。然后在最后一个元素被返回后(在第三次迭代时),会抛出StopIteration,这会停止生成器。while iterables始终保持为True

9

看起来这是文档中的一个错误。这个“等效”的代码在python2中可以正常运行,但在python3中却会陷入无限循环。

而且最新版本的文档也有同样的问题:http://docs.python.org/release/3.1.2/library/functions.html

看起来是变更61361导致了这个问题,因为它在没有确认这些改动对python3是否正确的情况下,直接合并了python 2.6的改动。

目前在主文档集中似乎没有这个问题,但你可能还是应该在http://bugs.python.org/上报告一下这个错误。

撰写回答