Python

FAQ: 数値の比較を is ですると一貫性がないのはなぜ?

More than 1 year has passed since last update.

>>> x = 100

>>> y = 100
>>> x == y
True
>>> x is y
True
>>> x = 1000
>>> y = 1000
>>> x == y
True
>>> x is y
False


is は同値ではなくて同一の比較

is 演算子は、左右が同じオブジェクトへの参照になっているかを比較します。次の例を見てください。

>>> x = []

>>> y = []
>>> x is y
False
>>> z = x
>>> x is z
True
>>> x.append(42)
>>> y
[]
>>> z
[42]

x と y は別々に作られた、別々のリストオブジェクトです。なので、 x is y は False になりますし、 x を変更しても y には影響しません。

一方、 z は x と同一のオブジェクトを参照しています。なので x is z は True になりますし、 x (が参照しているリストオブジェクト)を変更すると当然 z も同じように変化します。


整数型は immutable

オブジェクトが示す値が、オブジェクトを生成したときに決まり、その後変化しないようなオブジェクトを immutable といいます。

整数は immutable です。次のサンプルコードを見てください。

>>> x = 42

>>> y = x
>>> x is y
True
>>> x += 1
>>> x
43
>>> y
42
>>> x is y
False

y = x した直後は、 x と y は同じ 42 を表すオブジェクトを示しているので x is y は True でした。

x += 1 すると、 x には 43 を表す別のオブジェクトが代入されます。なので x is y が False になります。


Flyweight パターン

整数型のような immutable なオブジェクトが大量に使われるときに最適化のために使われるのが Flyweight パターンです。

新しい値が必要になったときに、その値のオブジェクトを毎回生成する変わりに、既にあるオブジェクトを共用することで、


  • 同じ値が何度も出現するときに1つのオブジェクトを利用することで、メモリ使用量を削減する

  • 同じ値のオブジェクトが何度も生成・破棄されることによるメモリ管理のコストを削減する

といったメリットがあります。

(2016/09/07現在) CPython の場合、 -5 から 256 までの整数が flyweight パターンで管理されていて、常に同じオブジェクトが使われるようになっています。なので、この範囲の値であれば、別々に作ったはずのオブジェクトでも x is y が True になったりします。