带/不带列表理解的python函数调用

Gah*_*han 12 python python-3.x

我有以下两个功能:

def foo(n=50000):
    return sum(i*i for i in range(n))  # just called sum() directly without 

def bar(n=50000):
    return sum([i*i for i in range(n)])  # passed constructed list to sum()
Run Code Online (Sandbox Code Playgroud)

我希望那foo会跑得更快,bar但我已经检查了ipython,%%timeitfoo时间稍长bar

In [2]: %%timeit
   ...: foo(50000)
   ...: 
100 loops, best of 3: 4.22 ms per loop

In [3]: %%timeit
   ...: bar(50000)
   ...: 
100 loops, best of 3: 3.45 ms per loop
In [4]: %%timeit
   ...: foo(10000000)
   ...: 
1 loops, best of 3: 1.02 s per loop

In [5]: %%timeit
   ...: bar(10000000)
   ...: 
1 loops, best of 3: 869 ms per loop
Run Code Online (Sandbox Code Playgroud)

的差随着予增加的n值从而我试图检查与功能dis.dis(foo)dis.dis(bar),但它是相同的.

那么这两种方法之间的时间差异会是什么原因呢?

Che*_* A. 6

关于发电机有很多很好的答案,所以我不会详细说明.

发电机保持状态.如果你进行非常快速的操作(比如使用sum,但是如果你使用I/O命令,则没有太大的区别),它们会稍微慢一些.生成器的优点是它们不会提前将所有项目加载到内存中,列表就是这样.

这是迭代列表时(在非常高级别)发生的情况:

  • 您将列表中的所有项目加载到内存中
  • 要求下一个元素只是给你指向该对象的指针

将其与发电机进行比较:

  • 你没有记忆中的所有物品.一次只有一个项目.
  • 请求下一个元素恢复生成器对象,运行代码直到它到达yield语句.
  • 然后它在内存中产生对象的地址,以便您可以访问它.

中间的这个额外步骤是测试中的差异.

所以,在你处理生成常用巨大的,需要到内存中加载的数据量.(对于协同程序的生成器有更多的用例,例如协同程序)

使用大文件和for循环打印行进行过期.在某些时候,使用列表时会出现内存不足的情况.然后尝试使用生成器,它们不会耗尽内存..