首页 > 解决方案 > itertools 中的 grouper() 示例

问题描述

我是python的新手。在阅读 python 标准库参考时,我对 itertools recipes 部分中的 grouper() 示例感到困惑。

我试图将示例代码放在一个小程序中,如下所示:

from itertools import zip_longest
import copy

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    args = [iter(iterable)] * n
    # print each string in args
    #c = copy.deepcopy(args)
    #for a in c:
    #    print(list(a))
    return zip_longest(*args, fillvalue=fillvalue)

def main():
    print("this is our first test script file")
    g = grouper('ABCDEFG', 3, 'x')
    # print each string in results
    #for s in g:
    #    print(list(s))

main()

如果我们删除评论标签,它会产生如下结果:

['A', 'B', 'C', 'D', 'E', 'F', 'G']
[]
[]
['A', 'B', 'C']
['D', 'E', 'F']
['G', 'x', 'x']

这对我来说看起来不对,因为 args 变量的结果是:

['A', 'B', 'C', 'D', 'E', 'F', 'G']
[]
[]

zip_longest() 调用如何产生如下结果?

['A', 'B', 'C']
['D', 'E', 'F']
['G', 'x', 'x']

它应该是 A,B,C,D,... 因为 args 中的第二个和第三个列表是空的。还是我错过了什么?

谁能给我解释一下?

标签: pythonpython-3.x

解决方案


zip并且与他们如何使用他们的论点zip_longest完全不同。deepcopy

grouper之所以有效,是因为每次从每个参数zipzip_longest获取一个元素。例如,考虑一下:

i1 = i2 = i3 = iter([1, 2, 3, 4, 5, 6])
zip(i1, i2, i3)

因为i1, i2, 和i3共享相同的迭代器,所以推进一个迭代器也会推进另一个迭代器。zip做这个:

  1. 从 中取一个元素i1
  2. 从 中取一个元素i2
  3. 从 中取一个元素i3
  4. 产生这些元素的元组。
  5. 从步骤 1 开始重复。

例如,会发生这样的事情:

第一次迭代:

  1. 从 中取一个元素i1。=>1
  2. 从 中取一个元素i2。=>2
  3. 从 中取一个元素i3。=>3
  4. 产生这些元素的元组 =>(1, 2, 3)

第二次迭代:

  1. 从 中取一个元素i1。=>4
  2. 从 中取一个元素i2。=>5
  3. 从 中取一个元素i3。=>6
  4. 产生这些元素的元组 =>(4, 5, 6)

现在,deepcopy在这种情况下,只复制迭代器。它不会以任何方式消耗它们。但是,您的for循环确实会消耗它们:

  1. i1. =>1, 2, 3, 4, 5, 6, StopIteration raised
  2. i2. =>StopIteration raised
  3. i3. =>StopIteration raised

因此,您会得到您所看到的结果。


推荐阅读