Python中yield返回列表的效率是否可以提高?

3
在 Python 2.7 中,如果我有一个像这样的函数:
def holes_between(intervals):
  # Compute the holes between the intervals, for example:
  #   given the intervals: ([ 8,  9] [14, 18] [19, 20] [23, 32] [34, 49])
  #     compute the holes: ([10, 13] [21, 22] [33, 33])
  prec = intervals[0][1] + 1 # Bootstrap the iteration
  for low, high in intervals[1:]:
    if prec <= low - 1:
      yield (prec, low - 1)
    prec = high + 1

holes = list(holes_between(intervals))

由于函数的 yield 被收集到一个 list 中,所以在 holes_between 函数内部构建该列表是否更有效率?如果是,最有效率的方法是什么?


你有一些样本输入来测试效率吗? - Martijn Pieters
2个回答

3

生成器函数比直接构建列表的效率可能低。

holes_between()函数中可以直接构建列表并返回:

def holes_between(intervals):
    prec = intervals[0][1] + 1 # Bootstrap the iteration
    result = []
    for low, high in intervals[1:]:
        if prec <= low - 1:
            result.append((prec, low - 1))
        prec = high + 1
    return result

但是要使用 timeit 模块 测试差异。

如果你有一些典型的输入,可以使用以下代码进行测试:

import timeit

def holes_between_list(intervals):
    prec = intervals[0][1] + 1 # Bootstrap the iteration
    result = []
    for low, high in intervals[1:]:
        if prec <= low - 1:
            result.append((prec, low - 1))
        prec = high + 1
    return result

def holes_between_generate(intervals):
    prec = intervals[0][1] + 1 # Bootstrap the iteration
    for low, high in intervals[1:]:
        if prec <= low - 1:
            yield (prec, low - 1)
        prec = high + 1

intervals = [ ... ] # fill in some test data

print 'As list:', timeit.timeit(
    'holes_between(intervals)',
    'from __main__ import intervals, holes_between_list as holes_between')

print 'Using a generator:', timeit.timeit(
    'list(holes_between(intervals))',
    'from __main__ import intervals, holes_between_generate as holes_between')

较小的值表示针对你的测试数据,方法速度更快。

0
总的来说,我认为惰性求值的灵活性比使用生成器可能带来的轻微性能损失更重要。在不使用枚举的所有元素的情况下,生成器方法的执行效果更好。
例如,假设您想要一个函数来检查间隔之间孔的最大阈值:
def threshold(intervals, n):
    for low, high in holes_between(intervals):
        if (high - low + 1) >= n:
            return True
    return False

如果间隔可迭代对象很大,当阈值早期超过时,您可以从生成器中受益,因为这样能够潜在地节省大量的工作。

如果这是您代码的关键部分,并且您已经测量了明确的性能问题,则可以将其重写为在holes_between函数中构建列表。如果您这样做,请务必对该函数进行基准测试,以查看是否真的提高了性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接