Python语法背后的基本原理

sus*_*its 11 python performance

for i in xrange(...)在Python中提倡使用-style循环结构的理由是什么?对于简单的整数循环,开销的差异很大.我使用两段代码进行了一个简单的测试:

档案idiomatic.py:

#!/usr/bin/env python

M = 10000
N = 10000

if __name__ == "__main__":
    x, y = 0, 0
    for x in xrange(N):
        for y in xrange(M):
            pass
Run Code Online (Sandbox Code Playgroud)

档案cstyle.py:

#!/usr/bin/env python

M = 10000
N = 10000

if __name__ == "__main__":
    x, y = 0, 0
    while x < N:
        while y < M:
            y += 1
        x += 1
Run Code Online (Sandbox Code Playgroud)

分析结果如下:

bash-3.1$ time python cstyle.py

real    0m0.109s
user    0m0.015s
sys     0m0.000s

bash-3.1$ time python idiomatic.py

real    0m4.492s
user    0m0.000s
sys     0m0.031s
Run Code Online (Sandbox Code Playgroud)

我可以理解为什么Pythonic版本更慢 - 我想它与调用xrange N次有很大关系,如果有一种方法可以倒回生成器,也许这可以消除.但是,由于执行时间的这种差异,为什么人们更喜欢使用Pythonic版本?

编辑:我使用Martelli先生提供的代码再次进行了测试,现在结果确实更好:

我以为我会在这里列举一下这个帖子的结论:

1)模块范围内的大量代码是个坏主意,即使代码包含在if __name__ == "__main__":块中也是如此.

2)*奇怪的是,修改属于thebadone我的错误版本的代码(让y增长而不重置)在性能上几乎没有差异,即使对于较大的M和N值也是如此.

Ale*_*lli 22

这是正确的比较,例如在loop.py中:

M = 10000
N = 10000

def thegoodone():
   for x in xrange(N):
       for y in xrange(M):
           pass

def thebadone():
    x = 0
    while x < N:
        y = 0
        while y < M:
            y += 1
        x += 1
Run Code Online (Sandbox Code Playgroud)

所有重要的代码都应该始终存在于函数中 - 在模块的顶层放置一亿个循环显示鲁莽地忽略性能并且嘲弄任何测量所述性能的尝试.

完成后,您会看到:

$ python -mtimeit -s'import loop' 'loop.thegoodone()'
10 loops, best of 3: 3.45 sec per loop
$ python -mtimeit -s'import loop' 'loop.thebadone()'
10 loops, best of 3: 10.6 sec per loop
Run Code Online (Sandbox Code Playgroud)

所以,正确衡量,你倡导的坏方法比Python推广的好方式慢约3倍.我希望这会让你重新考虑你的错误宣传.

  • @Federico,**速度**.变量get和set在函数中进行了高度优化,但不可能在模块顶层.例如,假设我的笔记本电脑和Glenn的机器是等价的,从我们的数字中你可以看到以正确的方式(功能中所有实质代码)与完全错误的方式(模块顶层的实质代码)做事情的因素.自己进行基准测试! - ) (6认同)
  • "所有重要的代码都应该始终存在于函数中 - 在模块的顶层放置一亿个循环显示出鲁莽的无视性能"(我明白了.)你能解释一下原因吗? (4认同)
  • @ 007brendan,模块级变量在模块外部(即其他模块)是可见的,因此应用它们的每一个小变化都必须立即应用,每次获取_must_都要从模块的dict重新完成,除非你能证明**否则100%确定......鉴于线程,这是不可能的.函数局部变量在函数实例之外是不可见的(更不易改变),它在任何半正式的Python实现中赋予了各种优化. (4认同)

Gle*_*ard 11

您忘记在内循环后将y重置为0.

#!/usr/bin/env python
M = 10000
N = 10000

if __name__ == "__main__":
    x, y = 0, 0
    while x < N:
        while y < M:
            y += 1
        x += 1
        y = 0
Run Code Online (Sandbox Code Playgroud)

编辑:修复后的20.63s与使用xrange的6.97s