通过 itertools 与直接 python 分块会给你带来额外的好处吗?

Does chunking via itertools vs straight python buy you anything extra?

我发现 two different waysiterable 拆分为 "chunks"(超过 1 项)。

One method uses itertools:

from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(*args, fillvalue=fillvalue)

the other method is straight python:

def chunker(seq, size):
    return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))

itertools 的实现能给你带来什么吗"extra"?

"extra" 可能会更快、更灵活或更安全。

我问是因为这里显示的 itertools 实现绝对不是 readable/intuitive IMO。

grouper 可以与 any iterable 一起使用——包括生成器和无限迭代器。 chunker 只能与 sequences 一起使用——其长度可预先知道的迭代器。

from itertools import izip_longest

def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(*args, fillvalue=fillvalue)

def chunker(seq, size):
    return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))

x = (i**2 for i in range(5))

print(list(grouper(x, 3)))
# [(0, 1, 4), (9, 16, None)]

print(list(chunker(x, 3)))
# TypeError: object of type 'generator' has no len()

这两个功能并不等同。有几点不同:

  • 您的 grouper 适用于任何可迭代对象,包括迭代器和生成器,而 chunker 需要支持索引的序列([...])。

    >>> it = lambda : (i for i in range(6))  # creates a generator when called
    >>> list(grouper(it(), 3))
    [(0, 1, 2), (3, 4, 5)]
    >>> list(chunker(it(), 3))
    TypeError: object of type 'generator' has no len()
    

    请注意,其他答案已经提到了这一点!

  • 如果块大小不是长度的约数,chunker最后一个元素将小于块大小。 OTOH grouper 将用一些填充值填充它。此外 chunker 将 return 与原始类型相同,而 grouper 将 return tuples:

    >>> list(grouper([1,2,3,4,5], 3))
    [(1, 2, 3), (4, 5, None)]
    >>> list(chunker([1,2,3,4,5], 3))
    [[1, 2, 3], [4, 5]]
    
  • grouper 使用高性能内置函数 iterzip_longest。这些将非常快。以牺牲可读性为代价。然而,这可以使它比 chunker:

    快得多
    l = list(range(10000))
    %timeit list(grouper(l, 10))
    # 320 µs ± 6.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    %timeit list(chunker(l, 10))
    # 1.22 ms ± 19 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

所以 grouper 是一种比 chunker 更快更通用的方法。但是,根据具体情况,使用 chunker 可能更有用,例如,如果您不喜欢 "fill" 部分或想要保留 "chunks".[= 的类型28=]