Python

Python での数値比較にisを使ってはいけない

環境

  • Python 3.6.4

結論

Pythonの数値比較ではisを使ってはいけません。

Pythonにおけるis==はそれぞれに用意されていてる用途に従って使いましょう。

  • is オブジェクトのidの比較
  • == オブジェクトの数値の比較

処理速度が速いからといってisで数値比較とかするのはNGです

コード

例えば、大抵の環境では

>>> a = 1
>>> a is 1
>>> True

となるので、うまく行っているように見えますが
実はこれはPythonがシングルトンで確保してくれてるだけです。

for i in range(255, 260):
    a = i
    print '{}: {}'.format(i, a is i+1-1)

>>> 255: True
>>> 256: True
>>> 257: False
>>> 258: False
>>> 259: False

実際のobjectのidを出力する方はこっち

for i in range(255, 260):
    a = i
    print '{}: {}: {}'.format(i, id(i), id(a+1-1))

>>> 255: 4406286672: 4406286672
>>> 256: 4406286704: 4406286704
>>> 257: 4409913072: 4410306320
>>> 258: 4410306384: 4410306320
>>> 259: 4409913072: 4410306320

Pythonは-5~256の整数値をシングルトンで確保しているようで、これら以外の数値は比較で使われるべきではありません。
ガーベジコレクトもありますし、少なくとも安全に使えるとはいえない気がします。
(gccollectが行われた場合の挙動については詳しくないです(´・ω・`))

きっかけ

isで整数値判定をしてたら時々挙動がおかしくなったことで判明

isの使い道

自分で生成したオブジェクトの同一性判定に使うべきだと思います。

巷でよく取り上げられる「None判定の時にisを使う方が良い」については経験的に多分正しいです。
ただ、例外的な使い方である気はします。

よく分からないこと

a = None
a is None

b = True
b is True

c = False
c is False

これらが常に安全にTrueになるかはよく分かりません。。
分かる人いたら教えてください(´・ω・`)