12

==Pythonを学び始めてから数日が経ちましたが、その時点でとに出くわしましたis。私が想定したJavaのバックグラウンドから来て、オブジェクトIDと値による==比較を行いますが、is

 >>> a = (1,2)
 >>> b = (1,2)
 >>> a is b
 False
 >>> a == b
 True

のようisに、Javaと同等で==あり、PythonはJava==と同等equals()です。isこれはとの違いについて考える正しい方法==ですか?それとも注意点がありますか?

4

4 に答える 4

22
  • '=='は等しいかどうかをチェックし、
  • 「is」はIDをチェックします

も参照してください

'=='または'is'のいずれかを使用してPythonで文字列を比較すると、異なる結果が生成されることがあるのはなぜですか?

于 2013-01-03T18:15:49.300 に答える
16

is両方のオペランドが同じオブジェクトであることを確認します。==左のオペランドを呼び出し__eq__()、右を渡します。通常、このメソッドは等式比較を実装しますが、他の目的でそれを使用するクラスを作成することは可能です(ただし、そうすべきではありません)。

一部の実装では、特定のオブジェクト(文字列リテラル、-1から256までの整数)で同じ結果が得られることに注意してください。ただし、これらの状況で演算子を置換可能と見なす必要があるという意味ではありませisん。==

于 2013-01-03T18:20:19.040 に答える
2

@CRUSADERの回答をフォローアップするには:

==eqメソッドを使用して、オブジェクトの同等性をチェックします。

isオブジェクトの実際のメモリ位置をチェックします。それらが同じメモリ位置である場合、それらは次のようにテストしますTrue

上で述べたように、最初の2 ** 8整数は速度を上げるためにメモリ位置に格納されるため、他のオブジェクトまたは256を超える整数を使用して何が起こっているかを確認します。例:


In [8]: a = 1001
In [9]: b = a # this sets a pointer to a for the variable b
In [10]: a == b 
Out[10]: True # of course they are equal
In [11]: a is b 
Out[11]: True # and they point to the same memory location
In [12]: id(a)
Out[12]: 14125728
In [13]: id(b)
Out[13]: 14125728

In [14]: b = 1001 #this instantiates a new object in memory In [15]: a == b Out[15]: True In [16]: a is b Out[16]: False #now the memory locations are different In [17]: id(a) Out[17]: 14125728 In [18]: id(b) Out[18]: 14125824

于 2013-01-03T20:31:11.480 に答える
1

これは、私が最初にこの回答を書いたときのように、一見同義の概念が新しいプログラマーを混乱させる可能性がある状況の1つです。あなたはJavaに基づく仮定に近かったが、逆行した。これらの演算子の違いは、オブジェクトの同等性とオブジェクトのIDの問題に要約されますが、想定とは逆に、==値でis比較し、オブジェクトIDで比較します。cpythonの組み込みドキュメントから(通訳者のプロンプトで入力して取得したものですが、ここからhelp("is")オンラインで入手することもできます):

アイデンティティの比較====================

演算子「is」と「isnot」は、オブジェクトの同一性をテストします。「x is y」は、xyが同じオブジェクトである場合にのみ真になります。オブジェクトIDは、「id()」関数を使用して決定されます。「xはyではありません」は逆真理値を生成します。

経験の浅いプログラマー(または実際には復習が必要な人)のためにこれを少し分解するために、各概念の大まかな定義を次のように示します。

  • オブジェクトの同等性:2つの参照が同じ有効値を持っている場合、それらは同等です。

  • オブジェクトの同一性:2つの参照が同じ正確なオブジェクト、たとえば同じメモリ位置を参照している場合、それらは同一です。

2 == 2オブジェクトの同等性は、またはを比較する場合など、予想されるほとんどの状況で発生します[0, None, "Hello world!"] == [0, None, "Hello world!"]。組み込み型の場合、これは通常、オブジェクトの値に基づいて決定されますが、ユーザー定義型は、__eq__メソッドを定義することで独自の動作を定義できます(ただし、オブジェクト)。オブジェクトの同一性は、同等性につながる可能性のあるものですが、全体として、完全に別の問題です。オブジェクトの同一性は、によって決定されるように、2つのオブジェクト(または2つの参照)がメモリ内のまったく同じオブジェクトを参照するかどうかに厳密に依存しますid()。同一の参照に関するいくつかの有用な注意:それらはメモリ内の同じエンティティを参照するため、常に(少なくともcpythonでは)同じ値を持ちます。__eq__型破りに定義されたため、同等になります。list.append()これは、またはなどのインプレース操作を介して参照の1つを変更しようとする場合にも当てはまり、my_object[0]=6IDをテストし、分離する必要のあるオブジェクトのコピーを作成するように注意する必要があります(これは次の主な目的の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を比較したい状況のために予約する必要があります。

于 2013-01-04T18:40:44.677 に答える