静かなる名辞

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



【python】rangeではin演算子が使える。速度は微妙かも

はじめに

 今日コードを書いていて、rangeでもinが使えることに気づきました。

>>> 10 in range(20)
True

 ドキュメントを見るとシーケンス型としての機能は一通り備えているようです。

range オブジェクトは collections.abc.Sequence ABC を実装し、包含判定、要素インデックス検索、スライシングのような機能を提供し、負のインデックスをサポートします (シーケンス型 — list, tuple, range を参照):

4. 組み込み型 — Python 3.6.5 ドキュメント

 ちなみにfloatでもなんとなくTrueになりましたが、あくまでも離散値の包含で比較される雰囲気です。

>>> 10.0 in range(20)
True
>>> 10.1 in range(20)
False

測ってみる

 こういうものがあると、速度が気になります。

>>> r = range(1000)
>>> l = list(range(1000))
>>> s = set(l)
>>> import timeit
>>> timeit.timeit(lambda : 500 in r)
0.2108146829996258
>>> timeit.timeit(lambda : 500 in l)
8.18245309899794
>>> timeit.timeit(lambda : 500 in s)
0.13419233300010092
>>> timeit.timeit(lambda : 0 <= 500 < 1000)
0.12016064700219431

 同じ長さのlistよりは圧倒的に速いものの、setに負けるという結果に。恐らくシーケンスに展開して線形探索をする訳ではないものの、内部処理がそこそこ複雑なのでしょう。また、単に値の区間だけ確認したいのなら、不等式による比較が最速のようです(setが異様に速いと言うべきか・・・)。

使いどころ

 rangeということはstepも入れられるので、複雑な条件のときにはmodで書くより可読性が良いかもしれません。

>>> [x in r for x in range(10)]
[True, False, False, True, False, False, True, False, False, True]

 他に積極的に使う理由は思いつきません。