pythonのisと==の違いを知りました

1 min read読了の目安(約1500字

はじめに

本記事で扱うこと

  • python における同一性
  • python の is の意味
  • python の==の意味
  • オブジェクトの比較

あらまし

python でコードを書いているとき、辞書ならびにオブジェクトを比較したい事案が発生しました。
そのため、以下のようなコードを書いて振る舞いを確認してみました。

私が思っていた挙動としては a == bFalse となることでしたが、予想に反して値が一緒であれば True になるようです。
細かい挙動について気になったため、==と is について調べることにしました。

a = {'x': 10, 'y': 20, 'z': {'a': 0, 'b': ['u']}}
b = {'x': 10, 'y': 20, 'z': {'a': 0, 'b': ['u']}}

print(a == b)
print(a is b)
print(id(a))
print(id(b))

"""
True
False
4543310848
4543656768
"""

pythonにおける同一性

https://docs.python.org/ja/3/reference/datamodel.html?highlight=mutable

python はすべてオブジェクトで表現されています。
このオブジェクトとはデータを抽象的に表したものです。

このとき、オブジェクトには 同一性 というものが設定されており、生成されたあとは変更されていません。
つまり、あるオブジェクトが必ずそのオブジェクト自身であることを保証・証明するものと考えることができます。

オブジェクトの同一性は id 関数で確認できます。

pythonにおけるis

python の is は、同一性を検証します。
つまり、完全に同じオブジェクトであるかを is 関数を用いて比較します。

よって、最初のコード例では a is bid(a) == id(b) は同じであり、同一性を検証します。

pythonにおける==

==演算子は、値自体を比較します。
そのため、同一性の比較ではありません。

実現方法として、__eq__というオブジェクトの特殊メソッドを == が実行時に呼び出すことで実現しています。

例えば、以下のように __eq__ を実装するとプロパティである x の絶対値が 1 以下であれば、値が等しいというクラスを定義できます。(実際にこういうのを使うかどうかは無視してください...)

from __future__ import annotations


class A:

    def __init__(self, x: int):
        self.x = x

    def __eq__(self, other: A):
        return abs(self.x - other.x) <= 1


v = A(x=0)
w = A(x=1)

print(v == w)
print(v is w)

"""
True
False
"""

オブジェクトの比較

python のオブジェクトの比較は、再帰的に 値が等しいか をチェックしています。
そのため、idの同一性ではなく実値自体を比較しています。

値を比較したいなら == を、真の意味で同じオブジェクトが調べるときは is を使うようにしようと思います。