この質問に対するPython 3の更新された回答を書いています。
どのようにされた__eq__Pythonで、どのような順序で処理?
a == b
一般に理解されていa == bますがa.__eq__(b)、常にそうであるとは限りませんtype(a).__eq__(a, b)。
明示的に、評価の順序は次のとおりです。
- 場合
bのタイプの厳密なサブクラス(ない同じタイプ)であるaS型」と持って__eq__、それを呼び出すとの比較が実施された場合に値を返し、
- そうでなければ、
a持って__eq__いる場合、それを呼び出し、比較が実装されている場合はそれを返します。
- それ以外の場合は、bを呼び出さなかったかどうかを
__eq__確認し、比較が実装されている場合はそれを呼び出して返します。
- それ以外の場合は、最後に、アイデンティティとの比較を行い
isます。
メソッドがを返す場合、比較が実装されていないかどうかがわかりますNotImplemented。
(Python 2では、__cmp__検索されたメソッドがありましたが、Python 3では廃止され、削除されました。)
BをサブクラスAにして、最初のチェックの動作を自分でテストしてみましょう。これは、受け入れられた回答がこのカウントで間違っていることを示しています。
class A:
value = 3
def __eq__(self, other):
print('A __eq__ called')
return self.value == other.value
class B(A):
value = 4
def __eq__(self, other):
print('B __eq__ called')
return self.value == other.value
a, b = A(), B()
a == b
これはB __eq__ called戻る前にのみ印刷されFalseます。
この完全なアルゴリズムをどのように知ることができますか?
ここでの他の答えは、私が情報を更新するつもりですので、不完全で古くなっているようだと、あなた自身のためにこれを調べることができるか、どのように示しています。
これはCレベルで処理されます。
ここでは、2つの異なるコードを確認する必要があり__eq__ます。クラスのオブジェクトのデフォルトと、デフォルトとカスタムのどちらを使用するかに関係なくobject、__eq__メソッドを検索して呼び出すコードです__eq__。
デフォルト __eq__
探し__eq__にアップし、関連するCのAPIドキュメントのショー私達__eq__によって処理されるtp_richcompareでいる- "object"で型定義cpython/Objects/typeobject.cで定義されているobject_richcompareためcase Py_EQ:。
case Py_EQ:
/* Return NotImplemented instead of False, so if two
objects are compared, both get a chance at the
comparison. See issue #1393. */
res = (self == other) ? Py_True : Py_NotImplemented;
Py_INCREF(res);
break;
したがって、ここでは、self == otherを返す場合True、それ以外の場合はNotImplementedオブジェクトを返します。これは、独自の__eq__メソッドを実装しないオブジェクトのサブクラスのデフォルトの動作です。
__eq__呼ばれる方法
次に、を呼び出すC APIドキュメントのPyObject_RichCompare関数を見つけますdo_richcompare。
次にtp_richcompare、"object"C定義用に作成された関数がによって呼び出されていることがわかりますdo_richcompareので、もう少し詳しく見てみましょう。
この関数の最初のチェックは、比較されるオブジェクトの条件です。
- 同じタイプではありませんが、
- 2番目の型は最初の型のサブクラスであり、
- 2番目の型には
__eq__メソッドがあり、
次に、引数を入れ替えて相手のメソッドを呼び出し、実装されている場合は値を返します。そのメソッドが実装されていない場合は、続行します...
if (!Py_IS_TYPE(v, Py_TYPE(w)) &&
PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) &&
(f = Py_TYPE(w)->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
次に__eq__、最初のタイプからメソッドを検索して呼び出すことができるかどうかを確認します。結果がNotImplementedでない、つまり実装されている限り、それを返します。
if ((f = Py_TYPE(v)->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
それ以外の場合は、他の型のメソッドを試さずにそこにある場合は、それを試し、比較が実装されている場合はそれを返します。
if (!checked_reverse_op && (f = Py_TYPE(w)->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
最後に、どちらのタイプにも実装されていない場合に備えて、フォールバックを取得します。
フォールバックは、オブジェクトのIDを確認します。つまり、メモリ内の同じ場所にある同じオブジェクトであるかどうかを確認します。これは、次の場合と同じですself is other。
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
結論
比較では、最初に比較のサブクラス実装を尊重します。
次に、最初のオブジェクトの実装との比較を試み、次に呼び出されなかった場合は2番目のオブジェクトとの比較を試みます。
最後に、同一性の比較のための同一性のテストを使用します。