优化对对象列表的所有元素调用方法

时间:2015-04-30 09:03:31

标签: python optimization

我有一个对象列表,我想遍历列表并为每个对象调用一个方法。显然,这是过度优化,更多的意思是“哦,我想知道什么是最快的方式”,而不是“必须拥有每个周期的速度”。我可以想到几种方法来实现这一点并对它们进行一些分析,从而给出了这些结果:

; 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解决方案看起来要快一些。

我错过了什么吗?

有更好的方法吗?

3 个答案:

答案 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方法快几个数量级