Python首选for语法的原因
为什么在Python中推荐使用for i in xrange(...)
这种循环方式呢?对于简单的整数循环来说,它们的开销差别很大。我做了一个简单的测试,使用了两段代码:
文件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
文件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
性能测试的结果如下:
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
我能理解为什么Python的写法会更慢——我想这和调用xrange N次有很大关系,或许如果有办法重置生成器,这个问题就能解决。不过,考虑到执行时间差别这么大,为什么还会有人选择使用Python的写法呢?
补充:我再次使用Mr. Martelli提供的代码进行了测试,结果确实有所改善:
我想在这里总结一下这个讨论的结论:
1) 在模块级别写很多代码是个坏主意,即使这些代码被放在if __name__ == "__main__":
这个块里。
2) *有趣的是,把thebadone
的代码改成我错误的版本(让y增长而不重置)对性能几乎没有影响,即使在M和N的值很大时也是如此。
5 个回答
3
适合遍历数据结构
for i in ...
这种写法非常适合用来遍历数据结构。在一些底层语言中,你通常需要通过一个整数来索引数组,但在Python中,这种写法让你可以省去索引的步骤。
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
修复后运行时间是20.63秒,而使用xrange时是6.97秒。
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
所有重要的代码应该总是放在函数里——在模块的最顶层放一亿个循环,这样做完全不考虑性能,也让任何尝试去测量性能的努力变得毫无意义。
一旦你这样做了,你会看到:
$ 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
所以,经过正确的测量,你提倡的那种糟糕的方法大约比Python推荐的好方法慢3倍。我希望这能让你重新考虑你错误的观点。