如何使用izip_longest取消代码以列出一个列表?

zfz*_*zfz 5 python iterator list python-itertools

最好的答案是什么是以块为单位迭代列表的最"pythonic"方式?使用函数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)
Run Code Online (Sandbox Code Playgroud)

我运行上面的代码,然后创建分块列表:

[1 ,2, 3, 4]
[5, 6, 7, 8]
[9, 10, None, None]
Run Code Online (Sandbox Code Playgroud)

我试着一步一步地运行它:

In [1]: args = [iter(range(10))] * 4

In [2]: args
Out[2]: 
[<listiterator at 0x1ad7610>,
 <listiterator at 0x1ad7610>,
 <listiterator at 0x1ad7610>,
 <listiterator at 0x1ad7610>]
Run Code Online (Sandbox Code Playgroud)

列表由同一个迭代器创建.我知道实现了izip_longest函数来生成列表对.如何通过izip_longest将迭代器转换为分块列表?谢谢.

Bre*_*arn 7

grouper函数只是使用自身的偏移版本来压缩原始的iterable.使用[iter(iterable)] * n创建一个列表,其中包含n对同一迭代器的引用.这些不是独立的副本; 它们都是对同一个对象的引用,所以推进它们都会提升它们.这是一个简单的例子:

>>> x = [1, 2, 3]
>>> a, b = [iter(x)] * 2
>>> next(a)
1
>>> next(b)
2
Run Code Online (Sandbox Code Playgroud)

izip_longest,比如zip,每个迭代器一次获取一个元素.首先,它从第一个可迭代中args获取第一个元素,这将是原始可迭代的第一个元素.但是当它抓住这个元素时,它会推进所有的迭代器,因为它们都是链接的.所以当izip_longest从下一个迭代器获取一个元素时,它将从原始的iterable中获取第二个元素.它继续这样下去; 每当它从一个迭代器中获取一个元素时,它就会前进所有这些元素,这样它从下一个迭代器中获取的项将成为原始迭代中的下一个项.