我正在看一些使用比较函数进行大量排序调用的代码,看起来应该使用关键函数.
如果你要改变seq.sort(lambda x,y: cmp(x.xxx, y.xxx)),这是更好的:
seq.sort(key=operator.attrgetter('xxx'))
Run Code Online (Sandbox Code Playgroud)
要么:
seq.sort(key=lambda a:a.xxx)
Run Code Online (Sandbox Code Playgroud)
我也有兴趣评论对现有代码进行更改的优点.
Ale*_*lli 21
"对现有代码进行更改"是程序演变的方式;-).编写一系列测试,使用现有代码提供已知结果,保存这些结果(在测试环境中通常称为"黄金文件"); 然后进行更改,重新运行测试,并验证(理想情况下是以自动方式)测试结果的唯一变化是那些专门用于那些的变化- 没有不希望的或意外的副作用.当然,人们可以使用更复杂的质量保证策略,但这是许多"集成测试"方法的要点.
至于编写简单key=函数的两种方法,设计意图是operator.attrgetter通过更专业化来加快速度,但至少在当前版本的Python中,速度没有可测量的差异.既然如此,对于这种特殊情况,我会推荐lambda,因为它更简洁和一般(我通常不是一个lambda爱好者,请注意! - ).
Mar*_*ers 10
当纯粹选择在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)
Run Code Online (Sandbox Code Playgroud)
所以应用attrgetter('bar')1000次比a快约40μs lambda.这是因为调用Python函数会产生一定的开销,而不是调用生成的本机函数attrgetter().
这种速度优势也转化为更快的排序:
>>> 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)
Run Code Online (Sandbox Code Playgroud)
正如之前的评论者所说,attrgetter速度稍快一些,但在很多情况下,差异很小(〜微秒)。
关于可读性,我个人更喜欢lambda它,因为它是人们以前在不同上下文中见过的结构,因此其他人可能更容易阅读和理解。
lambda另一项需要注意的是,与使用不同的是,在使用 时,您的 IDE 应该能够发出 attr 名称拼写错误的信号attrgetter。
一般来说,如果替代方案足够容易编写和阅读,我倾向于选择不需要额外导入的构造。
| 归档时间: |
|
| 查看次数: |
4985 次 |
| 最近记录: |