==
とis
Python には違いがありますか?
はい、非常に重要な違いがあります。
==
:等しいかどうかを確認-セマンティクスは、同等のオブジェクト(必ずしも同じオブジェクトである必要はない)が等しいかどうかをテストすることです。などのドキュメントは言います:
演算子<、>、==、> =、<=、!=は、2つのオブジェクトの値を比較します。
is
:アイデンティティをチェック-セマンティクスは、オブジェクト(メモリに保持されている)がオブジェクトであることです。再び、ドキュメントは言う:
事業者is
とis not
オブジェクトのアイデンティティのためのテストは:x is y
場合にのみ、真であるx
とy
同じオブジェクトです。オブジェクトIDは、id()
関数を使用して決定されます。x is not y
逆の真理値を生成します。
したがって、IDのチェックは、オブジェクトのIDの等価性のチェックと同じです。あれは、
a is b
と同じです:
id(a) == id(b)
ここで、id
は、「同時に存在するオブジェクト間で一意であることが保証されている」(を参照help(id)
)整数を返す組み込み関数であり、a
とb
は任意のオブジェクトです。
その他の使用方法
セマンティクスにはこれらの比較を使用する必要があります。is
身元の==
確認と等価性の確認に使用します。
したがって、一般的にはis
、身元の確認に使用します。これは通常、ドキュメント内で「シングルトン」と呼ばれる、メモリ内に1回だけ存在するはずのオブジェクトをチェックするときに役立ちます。
使用例is
:
None
- enum値(enumモジュールのEnumを使用する場合)
- 通常モジュール
- 通常、クラス定義から生じるクラスオブジェクト
- 通常、関数定義から生じる関数オブジェクト
- メモリ内に1度だけ存在する必要があるその他すべて(通常、すべてのシングルトン)
- IDによって必要な特定のオブジェクト
の通常の使用例は==
次のとおりです。
- 整数を含む数値
- 文字列
- リスト
- セット
- 辞書
- カスタムの可変オブジェクト
- 他の組み込み不変オブジェクト、ほとんどの場合
一般的なユースケースは、再び、について==
、あなたはないかもしれませんしたいオブジェクトで同じ代わりに、それはすることができ、オブジェクトの等価 1
PEP 8の方向
PEP 8は、標準ライブラリの公式Pythonスタイルガイドでも、次の2つの使用例is
について言及しています。
のようなシングルトンとの比較None
は、常にis
またはを
使用して行う必要がありますis not
。等価演算子は使用しないでください。
また、if x
あなたが本当に意味するif x is not None
とき-例えば、デフォルトである変数または引数がNone
他の値に設定されているかどうかをテストするとき- を書くことに注意してください。他の値には、ブール値のコンテキストではfalseになる可能性のあるタイプ(コンテナーなど)がある可能性があります。
アイデンティティからの平等の推論
場合はis
trueで、平等にすることができ、通常は推測される-オブジェクトは、それ自体であれば、論理的に、それは自分自身と同等にテストする必要があります。
ほとんどの場合、このロジックは真ですが、__eq__
特別なメソッドの実装に依存しています。ドキュメントは言います、
等価比較(==
および!=
)のデフォルトの動作は、オブジェクトのIDに基づいています。したがって、同じIDを持つインスタンスの等価比較は結果として等価となり、異なるIDを持つインスタンスの等価比較は結果として不等価となります。このデフォルトの動作の動機は、すべてのオブジェクトが再帰的である必要があるということです(つまり、xはyはx == yを意味します)。
一貫性のために、以下を推奨します。
平等比較は再帰的であるべきです。言い換えれば、同一のオブジェクトは同等に比較する必要があります。
x is y
意味する x == y
これがカスタムオブジェクトのデフォルトの動作であることがわかります。
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
対比も通常は真です-何かが等しくないとテストした場合、通常はそれらが同じオブジェクトではないと推測できます。
等価性のテストはカスタマイズできるため、この推論は必ずしもすべてのタイプに当てはまるわけではありません。
例外
注目すべき例外はnan
-それは常にそれ自身と等しくないとしてテストする:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
IDのチェックは、等価性のチェック(メンバーを再帰的にチェックする必要がある場合があります)よりもはるかに高速です。
ただし、等価として複数のオブジェクトが見つかる可能性がある場合は、等価の代わりにはなりません。
リストとタプルの同等性を比較すると、オブジェクトの同一性が同等であると想定されます(これは高速チェックであるため)。これは、ロジックに一貫性がない場合に矛盾が生じる可能性がありますnan
。
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
注意書き:
問題はis
、整数を比較するために使用することです。整数のインスタンスが、別の参照によって取得されたインスタンスと同じであると想定しないでください。この物語はその理由を説明しています。
コメンターには、Pythonでは、小さい整数(-5〜256を含む)がシングルトンであるという事実に基づいて、等しいかどうかをチェックする代わりに、コードがありました。
うわー、これはいくつかの陰湿なバグにつながる可能性があります。aとbは通常小さい数なので、aがbかどうかをチェックするコードがいくつかありました。バグは本番で6か月後に発生しました。これは、aとbが最終的にキャッシュされないほど十分に大きかったためです。– gwg
それは開発で働いた。ユニットテストに合格した可能性があります。
そして、それは本番環境で機能しました-コードが256より大きい整数をチェックするまで、その時点で本番環境で失敗しました。
これは、コードレビューまたはスタイルチェッカーで捕捉された可能性がある本番環境の障害です。
強調したいのはis
、整数の比較には使用しないことです。
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
出力:False True False
。