これは、私が最初にこの回答を書いたときのように、一見同義の概念が新しいプログラマーを混乱させる可能性がある状況の1つです。あなたはJavaに基づく仮定に近かったが、逆行した。これらの演算子の違いは、オブジェクトの同等性とオブジェクトのIDの問題に要約されますが、想定とは逆に、==
値でis
比較し、オブジェクトIDで比較します。cpythonの組み込みドキュメントから(通訳者のプロンプトで入力して取得したものですが、ここからhelp("is")
オンラインで入手することもできます):
アイデンティティの比較====================
演算子「is」と「isnot」は、オブジェクトの同一性をテストします。「x is y」は、xとyが同じオブジェクトである場合にのみ真になります。オブジェクトIDは、「id()」関数を使用して決定されます。「xはyではありません」は逆真理値を生成します。
経験の浅いプログラマー(または実際には復習が必要な人)のためにこれを少し分解するために、各概念の大まかな定義を次のように示します。
2 == 2
オブジェクトの同等性は、またはを比較する場合など、予想されるほとんどの状況で発生します[0, None, "Hello world!"] == [0, None, "Hello world!"]
。組み込み型の場合、これは通常、オブジェクトの値に基づいて決定されますが、ユーザー定義型は、__eq__
メソッドを定義することで独自の動作を定義できます(ただし、オブジェクト)。オブジェクトの同一性は、同等性につながる可能性のあるものですが、全体として、完全に別の問題です。オブジェクトの同一性は、によって決定されるように、2つのオブジェクト(または2つの参照)がメモリ内のまったく同じオブジェクトを参照するかどうかに厳密に依存しますid()
。同一の参照に関するいくつかの有用な注意:それらはメモリ内の同じエンティティを参照するため、常に(少なくともcpythonでは)同じ値を持ちます。__eq__
型破りに定義されたため、同等になります。list.append()
これは、またはなどのインプレース操作を介して参照の1つを変更しようとする場合にも当てはまり、my_object[0]=6
IDをテストし、分離する必要のあるオブジェクトのコピーを作成するように注意する必要があります(これは次の主な目的の1つですis
:エイリアスの検出と処理)。例えば:
>>> first_object = [1, 2, 3]
>>> aliased_object = first_object
>>> first_object is aliased_object
True
>>> aliased_object[0]= "this affects first_object"
>>> first_object
['this affects first_object', 2, 3]
>>> copied_object= first_object.copy() #there are other ways to do this, such as slice notation or the copy module, but this is the most simple and direct
>>> first_object is copied_object
False
>>> copied_object[2] = "this DOES NOT affect first_object"
>>> first_object
['this affects first_object', 2, 3]
>>> copied_object
['this affects first_object', 2, "this DOES NOT affect first_object"]
2つの参照がエイリアス化される可能性のある状況はたくさんありますが、代入演算子(上記のように、常に割り当てられたオブジェクトへの参照を作成します)の外では、それらの多くは正確な実装に依存します(Pythonのすべての実装ではありません)。同じ状況で文字列をインターンするか、同じ範囲の整数をプリエンプティブにキャッシュします(この場合の適切な用語はわかりません)。たとえば、私のcpythonのインストールでは、この記事が通常の範囲外であることを示唆しているように見える場合、起動時に-8をキャッシュしているようです。したがって、is
開発環境で機能しているように見える場合でも、同じ側にいて、一貫性のない動作を完全に回避し、を使用することをお勧めします==
。is
実際にIDを比較したい状況のために予約する必要があります。