代码之家  ›  专栏  ›  技术社区  ›  PaulMcG

lambda与operator.attrgetter('xxx')在Python中作为排序键函数

  •  28
  • PaulMcG  · 技术社区  · 15 年前

    如果你要改变 seq.sort(lambda x,y: cmp(x.xxx, y.xxx)) ,最好是:

    seq.sort(key=operator.attrgetter('xxx'))
    

    或:

    seq.sort(key=lambda a:a.xxx)
    

    我也有兴趣评论对现有代码进行修改的优点。

    2 回复  |  直到 6 年前
        1
  •  23
  •   Peter Mortensen icecrime    6 年前

    当你选择 attrgetter('attributename') lambda o: o.attributename 作为排序键,然后使用 attrgetter() 更快 两种选择中的一种。

    >>> from timeit import Timer
    >>> from random import randint
    >>> from dataclasses import dataclass, field
    >>> @dataclass
    ... class Foo:
    ...     bar: int = field(default_factory=lambda: randint(1, 10**6))
    ...
    >>> testdata = [Foo() for _ in range(1000)]
    >>> def test_function(objects, key):
    ...     [key(o) for o in objects]
    ...
    >>> stmt = 't(testdata, key)'
    >>> setup = 'from __main__ import test_function as t, testdata; '
    >>> tests = {
    ...     'lambda': setup + 'key=lambda o: o.bar',
    ...     'attrgetter': setup + 'from operator import attrgetter; key=attrgetter("bar")'
    ... }
    >>> for name, tsetup in tests.items():
    ...     count, total = Timer(stmt, tsetup).autorange()
    ...     print(f"{name:>10}: {total / count * 10 ** 6:7.3f} microseconds ({count} repetitions)")
    ...
        lambda: 130.495 microseconds (2000 repetitions)
    attrgetter:  92.850 microseconds (5000 repetitions)
    

    所以申请 attrgetter('bar') lambda . 那是因为打电话给 python 函数有一定的开销,比调用本机函数(如 吸引子()

    这种速度优势也转化为更快的排序:

    >>> def test_function(objects, key):
    ...     sorted(objects, key=key)
    ...
    >>> for name, tsetup in tests.items():
    ...     count, total = Timer(stmt, tsetup).autorange()
    ...     print(f"{name:>10}: {total / count * 10 ** 6:7.3f} microseconds ({count} repetitions)")
    ...
        lambda: 218.715 microseconds (1000 repetitions)
    attrgetter: 169.064 microseconds (2000 repetitions)
    
        2
  •  23
  •   Alex Martelli    15 年前

    “对现有的有效代码进行更改”是程序发展的方式;-)。编写一组好的测试,用现有代码给出已知的结果,保存这些结果(在测试上下文中通常称为“黄金文件”);然后进行更改,重新运行测试,并验证(理想情况下是以自动化的方式)对测试结果的唯一更改是那些特定的更改 去那里——没有不想要的或意想不到的副作用。当然,可以使用更复杂的质量保证策略,但这是许多“集成测试”方法的要点。

    至于两种写法简单吗 key= 功能,设计意图是 operator.attrgetter lambda ,只是因为它更简洁和一般(我通常不是一个lambda爱好者,提醒你!-)。

        3
  •  4
  •   YBadiss    6 年前

    正如先前的评论所说, attrgetter 稍微快一点,但在很多情况下,差别是微秒。

    lambda 因为这是一个人们以前在不同的语境中看到过的结构,所以对其他人来说可能更容易阅读和理解。

    另一个警告是,IDE应该能够在使用 λ 吸引子 .