【问题标题】:operator.itemgetter or lambdaoperator.itemgetter 或 lambda
【发布时间】:2013-06-19 01:54:30
【问题描述】:

我很好奇是否有任何迹象表明operator.itemgetter(0)lambda x:x[0] 哪个更好用,特别是在sorted() 中作为key 关键字参数,因为这是首先想到的用途。是否有任何已知的性能差异?是否有任何与 PEP 相关的偏好或指导?

【问题讨论】:

  • 我建议使用operator.itemgetter(0)
  • 甚至超过标准的可读性?这种基于性能的决策是不是过早的优化?
  • @hexparrot 这是一个很小的代码差异,我不认为可读性更好。我只是想知道将哪个“更好”集成到我的常规词典中。

标签: python python-2.7 python-3.x


【解决方案1】:

根据我对 1000 个元组列表的基准测试,使用 itemgetter 几乎是普通 lambda 方法的两倍。以下是我的代码:

In [1]: a = list(range(1000))

In [2]: b = list(range(1000))

In [3]: import random

In [4]: random.shuffle(a)

In [5]: random.shuffle(b)

In [6]: c = list(zip(a, b))

In [7]: %timeit c.sort(key=lambda x: x[1])
81.4 µs ± 433 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [8]: random.shuffle(c)

In [9]: from operator import itemgetter

In [10]: %timeit c.sort(key=itemgetter(1))
47 µs ± 202 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

我还测试了这两种方法在各种列表大小下的性能(以微秒为单位的运行时间)。

+-----------+--------+------------+
| List size | lambda | itemgetter |
+-----------+--------+------------+
| 100       | 8.19   | 5.09       |
+-----------+--------+------------+
| 1000      | 81.4   | 47         |
+-----------+--------+------------+
| 10000     | 855    | 498        |
+-----------+--------+------------+
| 100000    | 14600  | 10100      |
+-----------+--------+------------+
| 1000000   | 172000 | 131000     |
+-----------+--------+------------+

(生成上图的代码可以在here找到)

结合从列表中选择多个元素的简洁性,itemgetter 显然是在排序方法中使用的赢家。

【讨论】:

    【解决方案2】:

    撇开速度问题不谈,这通常取决于您在哪里创建 itemgetter 或 lambda 函数,我个人发现 itemgetter 非常适合一次获取多个项目:例如,itemgetter(0, 4, 3, 9, 19, 20) 将创建一个函数它返回传递给它的 listlike 对象的指定索引处的项的元组。要使用 lambda 执行此操作,您需要 lambda x:x[0], x[4], x[3], x[9], x[19], x[20],这要笨重得多。 (然后一些包,例如numpy 具有高级索引,它的工作原理很像itemgetter(),除了内置在普通括号符号中。)

    【讨论】:

    • +1 关于多个条目的好点,当然 itemgetter 是那里的赢家。
    【解决方案3】:

    itemgetter的性能略好:

    >>> f1 = lambda: sorted(w, key=lambda x: x[1])
    >>> f2 = lambda: sorted(w, key=itemgetter(1))
    >>> timeit(f1)
    21.33667682500527
    >>> timeit(f2)
    16.99106214600033
    

    【讨论】:

    • 但是这里测量的是 lambda 函数的创建。要测量排序本身,timeit 调用应该是 timeit(f1())timeit(f2())。还是我在这里遗漏了什么?
    • @dojuba timeit.timeit 如果参数不是字符串,则调用它。
    • 是的,但是谁在 python 中编写任何需要快速的东西
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 2019-08-15
    相关资源
    最近更新 更多