itertools中的grouper()示例

时间:2019-04-19 02:24:00

标签: python python-3.x

我是python的新手。在阅读python标准库参考时,我对itertools配方部分中的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中的第二个和第三个列表为空。还是我错过了什么?

有人可以向我解释吗?

2 个答案:

答案 0 :(得分:0)

常规zip函数采用最短的迭代器,并且仅将这些值压缩在一起,如果另一个列表较长,则只会忽略这些值。
 在下面,您可以看到第二个列表的长度为4,但是它忽略了最后一个元素 来自文档:https://docs.python.org/3.3/library/functions.html#zip

  

返回一个元组的迭代器,其中第i个元组包含每个自变量序列或可迭代对象中的第i个元素。当最短的输入可迭代耗尽时,迭代器停止。

print(list(zip([1,2,3],['A','B','C','D'])))
#[(1, 'A'), (2, 'B'), (3, 'C')]

而zip_longest需要最长的迭代器。 在下面,您可以看到第二个列表的长度为4,但是zip_longest并没有忽略它。
来自文档:https://docs.python.org/3.0/library/itertools.html#itertools.zip_longest

  

制作一个迭代器,该迭代器汇总每个可迭代对象中的元素。如果可迭代项的长度不均匀,则将缺失值填充为fillvalue。迭代一直持续到最长的可迭代耗尽为止。等效于:

import itertools as it
print(list(it.zip_longest([1,2,3],['A','B','C','D'])))
#[(1, 'A'), (2, 'B'), (3, 'C'), (None, 'D')]

fillvalue参数使用默认值填充缺失的值。例如下面我有fillvalue='X'

import itertools as it
print(list(it.zip_longest([1,2,3],['A','B','C','D'], fillvalue='X')))
#[(1, 'A'), (2, 'B'), (3, 'C'), ('X', 'D')]

答案 1 :(得分:0)

zipzip_longestdeepcopy相比,它们如何使用其参数。

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

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

由于i1i2i3共享相同的迭代器,因此推进一个也会推进另一个。 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

因此,您将获得看到的结果。