What is the most “pythonic” way to iterate over a list in chunks?中的最佳答案,使用 izip_longest 功能来列表列表。但我无法理解。
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
for item in grouper(range(10), 4):
print list(item)
我运行上面的代码,然后创建了分块列表:
[1 ,2, 3, 4]
[5, 6, 7, 8]
[9, 10, None, None]
我试图一步一步地运行它:
In [1]: args = [iter(range(10))] * 4
In [2]: args
Out[2]:
[<listiterator at 0x1ad7610>,
<listiterator at 0x1ad7610>,
<listiterator at 0x1ad7610>,
<listiterator at 0x1ad7610>]
列表由同一个迭代器创建。我知道实现了 izip_longest 功能来生成列表对。如何通过izip_longest将迭代器转换为分块列表?感谢。
答案 0 :(得分:6)
grouper
函数只是使用自身的偏移版本来压缩原始的iterable。使用[iter(iterable)] * n
创建一个列表,其中n
引用同一个迭代器。这些不是独立的副本;它们都是对同一个对象的引用,所以推进它们都会提升它们。这是一个简单的例子:
>>> x = [1, 2, 3]
>>> a, b = [iter(x)] * 2
>>> next(a)
1
>>> next(b)
2
izip_longest
与zip
一样,每次从每个迭代器获取一个元素。首先,它从args
中的第一个迭代中获取第一个元素,这将是原始可迭代的第一个元素。但是当它抓住这个元素时,它会推进所有的迭代器,因为它们都是链接的。因此,当izip_longest
从下一个迭代器获取一个元素时,它将从原始的iterable中获取第二个元素。它继续这样下去;每当它从一个迭代器中获取一个元素时,它就会前进所有这些元素,这样它从下一个迭代器中获取的项将成为原始迭代中的下一个项。