我是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中的第二个和第三个列表为空。还是我错过了什么?
有人可以向我解释吗?
答案 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)
zip
和zip_longest
与deepcopy
相比,它们如何使用其参数。
grouper
之所以有效,是因为zip
和zip_longest
每次从每个参数中取出一个元素。例如,考虑一下:
i1 = i2 = i3 = iter([1, 2, 3, 4, 5, 6])
zip(i1, i2, i3)
由于i1
,i2
和i3
共享相同的迭代器,因此推进一个也会推进另一个。 zip
这样做:
i1
中获取一个元素。i2
中获取一个元素。i3
中获取一个元素。在示例中,将发生以下情况:
第一次迭代:
i1
中获取一个元素。 => 1
i2
中获取一个元素。 => 2
i3
中获取一个元素。 => 3
(1, 2, 3)
第二次迭代:
i1
中获取一个元素。 => 4
i2
中获取一个元素。 => 5
i3
中获取一个元素。 => 6
(4, 5, 6)
现在,在这种情况下,deepcopy
仅复制迭代器。它不会以任何方式消耗它们。但是,您的for
循环会消耗掉它们:
i1
获取所有内容。 => 1, 2, 3, 4, 5, 6, StopIteration raised
i2
获取所有内容。 => StopIteration raised
i3
获取所有内容。 => StopIteration raised
因此,您将获得看到的结果。