Python生成器timeit

时间:2014-07-11 19:32:59

标签: python python-2.7

我试图在许多教程中理解Python生成器的人告诉他们它们比例如迭代列表快得多,所以我试一试,我写了一个简单的代码。我没想到那个时差会那么大,有人可以解释一下为什么吗?或许我在这里做错了。

def f(limit):
    for i in range(limit):
        if(i / 7.0) % 1 == 0:
            yield i

def f1(limit):
    l = []
    for i in range(limit):
        if(i / 7.0) % 1 == 0:
            l.append(i)
    return l


t = timeit.Timer(stmt="f(50)", setup="from __main__ import f")
print t.timeit()

t1 = timeit.Timer(stmt="f1(50)", setup="from __main__ import f1")
print t1.timeit()

结果: t = 0.565694382945 t1 = 11.9298217371

3 个答案:

答案 0 :(得分:3)

您没有公平地比较ff1

您的第一个测试只是测量Python 构建生成器对象需要多长时间。它永远不会迭代这个对象,这意味着f中的代码永远不会被实际执行(生成器只在迭代时执行它们的代码)。

然而,您的第二个测试会测量拨打f1所需的时间。意思是,它计算函数构造列表l所需的时间,运行for循环完成,多次调用list.append,然后返回结果。显然,这将比生成生成器对象慢得多。

为了公平比较,请将生成器f转换为列表:

t = timeit.Timer(stmt="list(f(50))", setup="from __main__ import f")

这将导致它完全迭代,这意味着现在将执行f内的代码。

答案 1 :(得分:1)

您计算创建生成器对象所需的时间。创建一个实际上并不执行任何代码,因此您实际上只是按照精心设计的方式执行任何操作。

修复之后,您会发现运行完成时生成器通常会稍微慢一些。它们的优点是它们不需要同时将所有元素存储在内存中,并且可以在中途停止。例如,当你有一系列布尔值并且想要检查它们中是否有任何一个是真的时,你需要首先计算所有值并创建一个列表,然后再检查真相,而对于生成器,你可以:

  • 创建第一个布尔值
  • 检查是否属实,如果是,请停止创建布尔值
  • 否则,创建第二个布尔值
  • 检查那个是否属实,如果是,则停止创建布尔值
  • 等等。

答案 2 :(得分:1)

https://wiki.python.org/moin/Generators在改进的效果部分提供了一些很好的信息。虽然创建一个生成器可能需要一些时间,但它提供了许多优点。

  • 使用较少的内存。通过逐个创建值,整个列表永远不会在内存中。
  • 开始时间较短。制作一个完整的列表需要时间,而生成器可以在创建第一个值时立即使用。
  • 生成器没有设定的结束点。

这是一个关于创建生成器和迭代器http://sahandsaba.com/python-iterators-generators.html的好教程。看看吧!