Python中zip(*[iter(s)]*n)是如何工作的?

126 投票
9 回答
36800 浏览
提问于 2025-04-15 19:05
s = [1,2,3,4,5,6,7,8,9]
n = 3

list(zip(*[iter(s)]*n)) # returns [(1,2,3),(4,5,6),(7,8,9)]

这个 zip(*[iter(s)]*n) 是怎么工作的?如果用更详细的代码来写,会是什么样子呢?


这是一个用于 将列表分割成相同大小块的技巧 - 可以查看那个问题,了解这个问题的整体情况。

9 个回答

35

我觉得在所有的回答中,有一点被忽略了(对那些熟悉迭代器的人来说可能很明显,但对其他人来说就不那么明显了)-

因为我们使用的是同一个迭代器,所以它会被消耗掉,剩下的元素会被zip函数使用。所以如果我们直接用列表,而不是用迭代器的话,比如:

l = range(9)
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate 
# output 
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)]

使用迭代器时,它会逐个取出值,只保留剩下的可用值,所以对于zip来说,一旦0被取走了,1就可以用了,然后是2,依此类推。这是一个非常微妙的点,但真的很聪明!!!

53

其他很棒的回答和评论很好地解释了参数解包zip()的作用。

正如Ignacioujukatzel所说,你把三个指向同一个迭代器的引用传给zip(),然后zip()会从每个引用中按顺序生成包含三个整数的元组:

1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9
^                    ^                    ^            
      ^                    ^                    ^
            ^                    ^                    ^

而且因为你想要一个更详细的代码示例:

chunk_size = 3
L = [1,2,3,4,5,6,7,8,9]

# iterate over L in steps of 3
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x
    end = start + chunk_size
    print L[start:end] # three-item chunks

根据startend的值:

[0:3) #[1,2,3]
[3:6) #[4,5,6]
[6:9) #[7,8,9]

顺便说一下,你也可以用map()来得到相同的结果,只需把初始参数设为None

>>> map(None,*[iter(s)]*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

想了解更多关于zip()map()的信息,可以查看这个链接:http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/

130

iter() 是一个用于遍历序列的工具。[x] * n 这个写法会生成一个列表,里面有 nx,也就是说这个列表的长度是 n,每个元素都是 x*arg 是把一个序列拆开,变成函数调用时的参数。所以你把同一个迭代器传给 zip() 三次,每次都会从这个迭代器中取出一个元素。

x = iter([1,2,3,4,5,6,7,8,9])
print(list(zip(x, x, x)))

撰写回答