为什么这个lambda涉及list.index()调用这么慢?

时间:2014-10-30 02:36:34

标签: python python-2.7 lambda cprofile

使用cProfile:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   17.834   17.834 <string>:1(<module>)
        1    0.007    0.007   17.834   17.834 basher.py:5551(_refresh)
        1    0.000    0.000   10.522   10.522 basher.py:1826(RefreshUI)
        4    0.024    0.006   10.517    2.629 basher.py:961(PopulateItems)
      211    1.494    0.007    7.488    0.035 basher.py:1849(PopulateItem)
      231    0.074    0.000    6.734    0.029 {method 'sort' of 'list' objects}
      215    0.002    0.000    6.688    0.031 bosh.py:4764(getOrdered)
     1910    3.039    0.002    6.648    0.003 bosh.py:4770(<lambda>)
      253    0.178    0.001    5.600    0.022 bosh.py:3325(getStatus)
        1    0.000    0.000    5.508    5.508 bosh.py:4327(refresh)
     1911    3.051    0.002    3.330    0.002 {method 'index' of 'list' objects}

1910 3.039 0.002 6.648 0.003 bosh.py:4770(<lambda>)行令我困惑。在bosh.py:4770我有modNames.sort(key=lambda a: (a in data) and data.index(a)),数据和modNames是列表。注意1911 3.051 0.002 3.330 0.002 {method 'index' of 'list' objects}似乎来自这一行。

那为什么这么慢?我可以用任何方式重写这个sort(),以便它的执行速度更快吗?

编辑:我失踪的最后一个成分是为了理解这个lambda:

>>> True and 3
3

1 个答案:

答案 0 :(得分:3)

正如YardGlassOfCode所述,它本身并不是lambda本身很慢,而是lambda内部的O(n)操作很慢。 a in datadata.index(a)都是O(n) operations,其中ndata的长度。作为对效率的额外侮辱,对index的呼吁也重复了a in data中所做的大部分工作。如果data中的项目是可以播放的,那么您可以通过首先准备一个字典来大大提高速度:

weight = dict(zip(data, range(len(data))))
modNames.sort(key=weight.get)  # Python2, or
modNames.sort(key=lambda a: weight.get(a, -1))  # works in Python3

这要快得多,因为each dict lookup is a O(1) operation

请注意,modNames.sort(key=weight.get)依赖于None比较小于整数:

In [39]: None < 0
Out[39]: True

在Python3中,None < 0会引发TypeError。因此,当lambda a: weight.get(a, -1)不在a时,weight用于返回-1。