通过itertools和直接python进行分块会为你带来额外的收益吗?

时间:2017-09-22 11:22:19

标签: python itertools readability

我遇到了two different waysiterable拆分为“块”(超过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实施是否会为您带来“额外”的收益?

“额外”的地方,可能更快,更灵活或更安全。

我问,因为这里显示的itertools实现肯定不是更易读/直观的IMO。

2 个答案:

答案 0 :(得分:5)

grouper可以与任何 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()

答案 1 :(得分:1)

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

  • 您的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()
    

    请注意,另一个答案已经提到了这一点!

  • 如果chunksize不是长度的除数,则chunker的最后一个元素将小于chunksize。 OTOH grouper将填充一些fillvalue。另外chunker将返回与原始相同的类型,而grouper将返回tuple s:

    >>> 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可能更有用,例如,如果您不喜欢“填充”部分或想要保留“块”的类型。