与列表理解相比,生成器速度较慢

Ari*_*ief 4 python performance

据我所知,当我们只想使用这些值一次时,我们可以使用生成器。使用下面的 2 个示例,我的逻辑是第二个应该更快,因为第一个首先创建一个列表,然后循环遍历值..而第二个仅处理来自生成器的值。然而,当我计算时间时,列表理解总是比生成器更快。为什么是这样?

第一:

x = []
a = time.perf_counter()
for j in [i**2 for i in range(20000)]:
    x.append(j)
print( time.perf_counter() - a )
Run Code Online (Sandbox Code Playgroud)

第二:

x = []
a = time.perf_counter()
for j in (i**2 for i in range(20000)):
    x.append(j)
print( time.perf_counter() - a )
Run Code Online (Sandbox Code Playgroud)

AKX*_*AKX 8

是的,生成器和geneexprs通常(呵呵)比列表推导式慢,但另一方面,它们是惰性评估的,并且您也不必为完全预先计算的列表支付内存成本。我想速度差异是由调用帧开销和(隐式或显式)yield抛出值引起的。

使用您的代码,但timeit要对其进行测量,并使用生成器函数的第三个版本:

import timeit

def f1():
    x = []
    for j in [i**2 for i in range(20000)]:
        x.append(j)
    return x

def f2():
    x = []
    for j in (i**2 for i in range(20000)):
        x.append(j)
    return x


def f3():
    def gen():
        for i in range(20000):
            yield i ** 2
    x = []
    for j in gen():
        x.append(j)
    return x


print(timeit.timeit(f1, number=100))
print(timeit.timeit(f2, number=100))
print(timeit.timeit(f3, number=100))
Run Code Online (Sandbox Code Playgroud)

结果(Python 3.7.0)似乎表明geneexprs 与生成器函数一样快,比列表理解慢大约 4-5%。

f1 = 2.882695159
f2 = 3.0303254170000002
f3 = 3.002670741
Run Code Online (Sandbox Code Playgroud)