在Python中名称查找相对昂贵,因此对于大型循环,您可以通过更改
之类的内容来获得性能优势for element in my_list:
do_something(element)
类似
ds = do_something
for element in my_list:
ds(element)
这样解释器只需要在每次迭代时查找局部变量。如果列表推导调用函数,这种优化也很有用吗?
答案 0 :(得分:1)
是。我使用timeit
:
from __future__ import print_function
import timeit
setup = '''
def return_five():
return 6
def f1():
return [return_five() for i in range(10000)]
def f2():
r = return_five
return [r() for i in range(10000)]
'''
print('Not a local variable:')
print(min(timeit.Timer('a = f1()', setup=setup).repeat(7, 1000)))
print('Local variable:')
print(min(timeit.Timer('a = f2()', setup=setup).repeat(7, 1000)))
此脚本的典型结果是
Not a local variable:
1.22310686111
Local variable:
1.17974805832
我惊讶地发现第二个函数f2
始终比第一个函数快3.5%。我期待Python在return_five
遇到列表理解时只查找f1
一次,但它似乎每次都会查找它。
(据推测,如果所涉及的一个函数具有以某种方式更改名称查找的副作用,列表理解就会正常运行。这对我来说似乎是一种非常病态的副作用,但我想最好稍微改一下效率低于引入可能导致难以追踪的错误的优化。)
当我将列表推导的大小从10,000更改为10时,差距已关闭,因此f2
仅比f1
快0.8%。这确认了函数名称查找是在循环的每次迭代中执行的。