Pythonの==演算子とis演算子の違い
Pythonにおいて、==
演算子は2つのオブジェクトの値が等価(同値)かを比較・判定し、is
演算子は2つのオブジェクトが同一かを比較・判定する。
==演算子は等価比較
==
演算子は2つのオブジェクトの値が等しければTrue
、等しくなければFalse
を返す。
a = 100
b = 100
c = 200
print(a == b)
# True
print(a == c)
# False
反対に、!=
演算子は2つのオブジェクトの値が等しくなければTrue
、等しければFalse
を返す。
print(a != b)
# False
print(a != c)
# True
注意点: 数値に対する等価比較
整数int
や浮動小数点数float
、複素数complex
などの数値を表す型の場合、異なる型であってもその値をもとに比較される。
print(100 == 100.0)
# True
print(100 == 100 + 0j)
# True
さらに、真偽値bool
は整数int
のサブクラスであり、True
は1
、False
は0
とみなされる。
print(1 == True)
# True
print(0.0 == False)
# True
値も型も等しいか判定したい場合はtype()
とand
を使う。
a = 100
b = 100.0
print(a == b)
# True
print(a == b and type(a) == type(b))
# False
なお、文字列str
は内容に関わらず数値と等価とは判定されない。文字列が表す値を数値と比較したい場合はint()
やfloat()
で文字列を数値に変換する。
print(100 == '100')
# False
print(100 == int('100'))
# True
is演算子はオブジェクトの同一性比較
is
演算子は2つのオブジェクトが同一であればTrue
、同一でなければFalse
を返す。
同じ値(==
の結果がTrue
)であっても、異なるオブジェクトであればis
はFalse
を返す。
l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(l1 == l2)
# True
print(l1 is l2)
# False
変数を別の変数に代入するような場合は、2つの変数が同じオブジェクトを指すのでis
はTrue
を返す。
l3 = l1
print(l1 is l3)
# True
リストや辞書などのイミュータブル(変更可能)なオブジェクトでは、2つの変数が同じオブジェクトを指しているときに一方を変更すると他方も変更される。
l1[0] = 100
print(l1)
# [100, 2, 3]
print(l2)
# [1, 2, 3]
print(l3)
# [100, 2, 3]
is
演算子とは反対に、is not
演算子は2つのオブジェクトが同一でなければTrue
、同一であればFalse
を返す。
print(l1 is not l2)
# True
print(l1 is not l3)
# False
同一性はid()関数で判定される
オブジェクトの同一性の判定には、オブジェクトの識別値を返す組み込み関数id()
が使われる。
print(id(l1))
# 4388188480
print(id(l2))
# 4388187456
print(id(l3))
# 4388188480
同一オブジェクト(例ではl1
とl3
)が同じ識別値であることが確認できる。
注意点: イミュータブルな型の同一性比較
整数int
や文字列str
などのイミュータブル(変更不可)な型のオブジェクトに対するis
やis not
での比較は注意が必要。
新たにオブジェクトを生成したときに、既存のオブジェクトへの参照が返される場合とそうでない場合がある。
例えばint
の場合、-5
から256
の範囲の値を生成すると既存のオブジェクトへの参照が返されるが、その範囲外の値は別のオブジェクトとして生成される。
The current implementation keeps an array of integer objects for all integers between
-5
and256
. When you create an int in that range you actually just get back a reference to the existing object. 整数型オブジェクト (integer object) — Python 3.11.3 ドキュメント
a = 256
b = 256
print(a is b)
# True
a = 257
b = 257
print(a is b)
# False
文字列str
の場合、英数字とアンダースコア_
のみの文字列はキャッシュされ、以降はそのオブジェクトへの参照が返されるが、他の文字を含む文字列は別のオブジェクトとして生成される。
a = 'abc_123'
b = 'abc_123'
print(a is b)
# True
a = 'abc_123?'
b = 'abc_123?'
print(a is b)
# False
さらに、例えば、2つの変数への代入を1行で書くと同一オブジェクトになるなど、書き方によって結果が異なる場合がある。
a, b = 257, 257
print(a is b)
# True
a, b = 'abc_123?', 'abc_123?'
print(a is b)
# True
また、これらはCPython 3.11で実行した場合の結果であり、実装やバージョンによって異なる可能性もある。
is
の方が==
より高速なので、仕様を熟知した上でis
を使うケースはあるかもしれないが、基本的にはイミュータブルなオブジェクトに対してはis
ではなく==
で比較すればよい。
==演算子はオーバーロード可能、is演算子は不可
==
演算子と!=
演算子には、対応する特殊メソッド__eq__
と__ne__
があり、オーバーロード可能。
class MyClass:
def __eq__(self, other):
return '__eq__'
def __ne__(self, other):
return '__ne__'
my_obj = MyClass()
print(my_obj == 100)
# __eq__
print(my_obj != 100)
# __ne__
上は==
, !=
演算に対して常に'__eq__'
, '__ne__'
を返すという極端な例だが、ユーザー定義クラスの==
, !=
演算は独自にカスタマイズされている可能性がある。
一方、is
演算子とis not
演算子には対応する特殊メソッドがなく、オーバーロードできない。必ずオブジェクトの同一性を比較・判定される。
Noneの判定は"is None"または"is not None"
None
は値が存在しないことを表す組み込み定数。
- 関連記事: PythonにおけるNoneの判定
Pythonのコーディング規約PEP8において、None
との比較は==
, !=
ではなくis
, is not
を使うべき、と記載されている。
None
のようなシングルトンと比較をする場合は、常にis
かis not
を使うべきです。絶対に等値演算子を使わないでください。 プログラミングに関する推奨事項 — pep8-ja 1.0 ドキュメント
a = None
print(a is None)
# True
print(a is not None)
# False
PEP8には明記されていないが、以下の理由が考えられる。
None
はシングルトン(NoneType
型の唯一のインスタンス)だから- 上述の整数や文字列の例のように
is
の結果が値によって変わる懸念がない
- 上述の整数や文字列の例のように
is
,is not
はオーバーロード不可で安全だから==
,!=
は演算子オーバーロードによってカスタマイズされている可能性がある
is
,is not
の方が==
,!=
より高速だから
2番目の理由の例。__eq__
の実装によっては== None
はNone
でない値に対してもTrue
を返す可能性がある。is None
は常に正しく判定される。
class MyClass:
def __eq__(self, other):
return True
my_obj = MyClass()
print(my_obj == None)
# True
print(my_obj is None)
# False
なお、非数を表すnan
はfloat
型の値でありNone
とは別物。nan
の判定にはmath.isnan()
などを使う。
- 関連記事: Pythonにおけるnanの判定