@zenpoyはパフォーマンスを懸念していたため、ここで示した2つの選択肢の速度をテストしました。
テストスクリプト:
import random
from collections import namedtuple
from timeit import timeit
from operator import attrgetter
runs = 10000
size = 10000
random.seed = 42
Person = namedtuple('Person', 'name,age')
seq = [Person(str(random.randint(0, 10 ** 10)), random.randint(0, 100)) for _ in range(size)]
def attrgetter_test_name():
return sorted(seq.copy(), key=attrgetter('name'))
def attrgetter_test_age():
return sorted(seq.copy(), key=attrgetter('age'))
def lambda_test_name():
return sorted(seq.copy(), key=lambda x: x.name)
def lambda_test_age():
return sorted(seq.copy(), key=lambda x: x.age)
print('attrgetter_test_name', timeit(stmt=attrgetter_test_name, number=runs))
print('attrgetter_test_age', timeit(stmt=attrgetter_test_age, number=runs))
print('lambda_test_name', timeit(stmt=lambda_test_name, number=runs))
print('lambda_test_age', timeit(stmt=lambda_test_age, number=runs))
結果:
attrgetter_test_name 44.26793992166096
attrgetter_test_age 31.98247099677627
lambda_test_name 47.97959511074551
lambda_test_age 35.69356267603864
ラムダの使用は確かに遅くなりました。最大10%遅くなります。
編集:
さらにテストすると、複数の属性を使用して並べ替えた場合の結果が示されます。同じ設定で次の2つのテストケースを追加しました。
def attrgetter_test_both():
return sorted(seq.copy(), key=attrgetter('age', 'name'))
def lambda_test_both():
return sorted(seq.copy(), key=lambda x: (x.age, x.name))
print('attrgetter_test_both', timeit(stmt=attrgetter_test_both, number=runs))
print('lambda_test_both', timeit(stmt=lambda_test_both, number=runs))
結果:
attrgetter_test_both 92.80101586919373
lambda_test_both 96.85089983147456
ラムダはまだアンダーパフォームしていますが、それほどではありません。現在、約5%遅くなっています。
テストはPython3.6.0で行われます。