静かなる名辞

pythonとプログラミングのこと


【python】operator.itemgetterを使うべきか否か問題

はじめに

 この記事を開いた人の大半は「itemgetter? なにそれ」という反応でしょう。
 (いや、検索で来た人はそうでもないかもしれないけど)

 itemgetterは以下のように使えるものです。

>>> lst = list(zip([1,3,5,6,7,1,4], [3,4,1,0,8,5,2]))  # 特に値に意味はない
>>> sorted(lst, key=lambda x:x[0])
[(1, 3), (1, 5), (3, 4), (4, 2), (5, 1), (6, 0), (7, 8)]
>>> sorted(lst, key=lambda x:x[1])
[(6, 0), (5, 1), (4, 2), (1, 3), (3, 4), (1, 5), (7, 8)]
>>> from operator import itemgetter
>>> sorted(lst, key=itemgetter(0))
[(1, 3), (1, 5), (3, 4), (4, 2), (5, 1), (6, 0), (7, 8)]
>>> sorted(lst, key=itemgetter(1))
[(6, 0), (5, 1), (4, 2), (1, 3), (3, 4), (1, 5), (7, 8)]

 つまり、itemgetter(0)はlambda x:x[0]と等価です。

 参考:
 10.3. operator — 関数形式の標準演算子 — Python 3.6.5 ドキュメント

 では、どちらを使うべきなのでしょうか?



 目次

可読性とタイプ数

可読性

 可読性は正直なんとも言い難いです。

 とりあえずlambda式はlambda式の概念さえ理解していればわかるともいえますし、それでもわかりづらいという人もいるでしょう。また、見た目はグロいです。

 itemgetterは見た目はすっきりしています。これはとても大切なことで、lambdaまみれで入り組んだコードはもううんざりです。ただ、itemgetter自体を知らない人は恐らく多いので、初見では「helpを見る」「ググる」という作業が発生します。また、何をやっているか明示的にわかりづらいので、lambdaの方がマシという考え方もあります。

タイプ数

 タイプ数的には、はじめにを見て頂ければわかる通り互角です。itemgetterという途方もなく長い識別子のせいで、lambda式に勝てません。

 一応、asで別名にしてしまうという反則技(?)はあります。

from operator import itemgetter as get  # もうちょっと良い名前を考えて

 こうするとタイプ数的にはlambdaに勝てそうです。ただ、こうするのは如何なものか? と相成ります。混乱を招きそうなので、あまりやりたくない手です。

結論

 可読性・タイプ数では決められない。

速度差

 まさかこんなのに速度差なんてねーだろ、そう思っていた時期が私にもありました。

 都合によりminで比較。こうすると常に全数線形探索されるはずなので、再現性等が良いです。

>>> import timeit
>>> lst = list(zip(range(10000), range(10000)))
>>> timeit.timeit(lambda :min(lst, key=lambda x:x[0]), number=1000)
1.33255122898845
>>> timeit.timeit(lambda :min(lst, key=itemgetter(0)), number=1000)
0.6424821490072645

 倍違うのだった。えぇ・・・

 怪しいので、key関数を外部に定義してみます。

>>> key1 = lambda x:x[0]
>>> key2 = itemgetter(0)
>>> timeit.timeit(lambda :min(lst, key=key1), number=1000)
1.32674505902105
>>> timeit.timeit(lambda :min(lst, key=key2), number=1000)
0.6525059329869691

 変わらず。

結論

 速いので、特にこだわりがなければitemgetterを使いましょう。

 私はわざわざimportするのがダルいのと、個人的にlambdaがそれなりに好きという理由でlambdaを使い続けると思います。競プロとかのときはitemgetter有利なんじゃないでしょうか。