Pythonのisと==の違いを理解する【オブジェクトの同一性と同値性】
混乱しやすいPythonのisと==演算子の違いを解説します。
Pythonにおいて、二つのオブジェクトが等しいかどうかを判定する場合、同一である場合と同値である場合の2つのパターンがあります。それぞれ、is
演算子と==
演算子で二つの変数を比較して同一か同値かを判定することができます。
それぞれの違いを理解しないと、実装面で思わぬバグが生まれてしまうため、しっかりと理解したいポイントです。
オブジェクトの同一性と同値性(等価性)とは?
Pythonにおいて『オブジェクトが同一である』とは、メモリ上のアドレスが同じオブジェクトを指すことを言います。同じオブジェクトを指しているわけなので、当然その中身である値も同じになります。
一方で、『オブジェクトが同値である』とは、変数の値が同じであるという意味です。同じオブジェクトであろうがなかろうが、比較している変数に格納されているオブジェクトの値が同じであれば同値であると言えます。つまり、二つの変数を比較した時に、『同値ではあるが、同一ではない』ということはあり得ますが、『同一ではあるが、同値ではない』ということはあり得ません。
以下では、同一性と同値性の判定方法を解説しながら、それぞれの内容を詳しくみていきます。
is演算子と==演算子によるオブジェクトの比較
Pythonでは、同一のオブジェクトかどうかを判定するにはis
演算子を使います。is
演算子は、二つの変数が同じアドレス上のオブジェクトを指している場合にTrue
を返し、そうでなければFalse
を返します。
また、同値のオブジェクトかどうかを判定するには==
演算子を使います。二つの変数が別のアドレスのオブジェクトであっても、等しい値を保持していればTrue
を返し、そうでなければFalse
を返します。
例えば、次のようにx
とy
という2つの変数があったとします。先に結論をいうと、この二つのオブジェクトは同値ですが、同一ではありません。
# xとyは同値だが、同一ではない
x = [1, 2, 3]
y = [1, 2, 3]
# xとyは同値
print(x == y)
# True
# xとyは同一ではない
print(x is y)
# False
x
とy
はまったく同じ要素を保有するリストなので、同値です。そのため、x == y
という条件式を評価すると、True
が返されます。
しかし、同じ値を保持していても、それぞれ別の変数に代入されているため、同一ではありません。そのため、x is y
という条件式を評価すると、False
が返されます。これは、x
とy
が指すリストは、異なるオブジェクトであるためです。
二つの変数が同一のオブジェクトである場合には、定義上、それぞれの変数はメモリ上の同じアドレスを指すことになります。Pythonで特定のオブジェクトのアドレスを確認するためには、組み込み関数のid()
を使用します。つまり、x is y
とid(x) == id(y)
の条件式は同じことをしています。
試しに、x
をy
に代入して、x
とy
が同一のオブジェクトを指すことを確認してみましょう。
# id関数でアドレスを確認すると、異なるオブジェクトだとわかる
print(id(x))
# 140606917707776
print(id(y))
# 140606917706112
# yにxを代入すると、同一のオブジェクトになる
y = x
print(x is y)
# True
# 同一のオブジェクトのため、同じアドレスを指すようになる
print(id(x))
# 140606917707776
print(id(y))
# 140606917707776
ちなみに、それぞれの演算子では以下のような形で否定形を使うことができます。
- 同一ではないことを確認する:
x is not y
- 同値ではないことを確認する:
x != y
それぞれ、同一・同値ではない場合にTrue
を返し、同一・同値である場合にFalse
を返します。
immutableなオブジェクトのis演算子の評価には注意する
Pythonのデータ型には、オブジェクトの値を変更可能なmutable
と、オブジェクトの値を変更不可能なimmutable
が存在します。
mutable
なデータ型の変数では、オブジェクトのid(メモリ上のアドレス)を変えずに、値を変えることができます。一方、immutable
なデータ型の変数では、同じオブジェクトの中で値を変えることができません。つまり、immutable
なデータ型の変数に別の値を代入すると、中身の値が新しくなるのではなく、別のアドレス上の新しいオブジェクトが生成されることになります。
代表的なデータ型でいうと、リストや辞書、Set型などはmutable
(変更可能)で、文字列やint
型、タプルなどはimmutable
(変更不可)です。
前述したリストのようなmutable
なデータ型の同一性を比較する場合には、is
演算子を使うことで、比較する二つのオブジェクトが同じidを指しているかどうかを確認していました。しかし、immutable
なデータ型の同一性を比較する場合には注意が必要です。
immutalbe
なオブジェクトであるstr
型の比較について例を見てみましょう。
# 同値なstr型の変数を定義
x = "abc"
y = "abc"
# xとyは同値である
print(x == y)
# True
# xとyは同一と判定される
print(x is y)
# True
# idを確認しても同じ
print(id(x))
# 140606914954416
print(id(y))
# 140606914954416
str
型で定義した二つの変数x
とy
に対して、x is y
という条件式で評価すると、True
が返されます。
これは、文字列が不変なオブジェクト(immutable
)であるため、同じ値を持つ変数がすでに定義されている場合には、同じアドレスを参照する場合があるためです。特定のアドレス上のデータの値が変わらないことが保証されている(immutable
)のであれば、わざわざ別のアドレスに同じ値を作る必要はないので、データを効率よく扱うための仕組みと言えます。
ただ、immutable
なデータ型のオブジェクトを同じ値で複数生成したときに、必ずしも同じアドレスを参照するとは限らないので注意してください。