我有一个对象列表,我想遍历列表并为每个对象调用一个方法。显然,这是过度优化,更多的意思是“哦,我想知道什么是最快的方式”,而不是“必须拥有每个周期的速度”。我可以想到几种方法来实现这一点并对它们进行一些分析,从而给出了这些结果:
; ipython
Python 2.7.5 (default, Jun 17 2014, 18:11:42)
Type "copyright", "credits" or "license" for more information.
IPython 2.3.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1] class ook:
def eek(self):
pass
In [2] lst = [ook(), ook(), ook(), ook(), ook(), ook(), ook(), ook()]
In [3] %timeit -n 10000 map(lambda x: x.eek(), lst)
10000 loops, best of 3: 2.17 µs per loop
In [4] %timeit -n 10000 [x.eek() for x in lst]
10000 loops, best of 3: 2.32 µs per loop
In [5] def test(lst):
for x in lst:
x.eek()
In [6] %timeit -n 10000 test(lst)
10000 loops, best of 3: 2.18 µs per loop
标准循环方法似乎在可读性方面获胜,但map
解决方案看起来要快一些。
我错过了什么吗?
有更好的方法吗?
答案 0 :(得分:3)
如果您只想调用列表中的所有函数,for循环应该是最有效的,因为它不会创建新列表(它实际上是我机器上最有效的函数)。
另请注意,在Python 3中, map 解决方案不起作用,因为它会创建稍后要评估的生成器。
答案 1 :(得分:1)
使用更大的数组(1000个),普通循环更快(在我的测试中),然后是列表理解,然后(慢60%)map方法。
普通循环最快的原因(可能)是它不必将返回值收集到新列表中。映射变得如此慢的原因是它需要为每次迭代进行额外的函数调用(lambda)。
然而,在现实生活中,与实际eek()
方法所花费的时间相比,任何这些方法的开销可能都是微不足道的。
答案 2 :(得分:1)
@Sandathrion,在评论中回答您的其他问题“您能否通过上面的玩具示例创建一个如何做到这一点的答案?”这很难,因为玩具示例没有做任何事情,但如果使用几乎简单的示例将类属性从0更改为1超过1,000个对象:
import timeit
### values held externally in numpy array
setup = """
import numpy as np
N = 1000
class ook(object):
def __init__(self, i):
self.ook_index = i
ook_vals = np.zeros(N)
lst = [ook(i) for i in range(N)]
"""
fn = """
ook_vals[:] = 1
"""
print(timeit.timeit(fn, setup, number=10000) / 10000)
### values held in class instances
setup = """
N = 1000
class ook(object):
def __init__(self):
self.val = 0
def eek(self):
self.val = 1
lst = [ook() for i in range(N)]
"""
fn = """
for x in lst:
x.eek()
"""
print(timeit.timeit(fn, setup, number=10000) / 10000)
结果
3.43601703644e-06
0.00044386138916
即。 numpy方法快几个数量级