이 질문에 대한 Python 3에 대한 업데이트 된 답변을 작성하고 있습니다.
__eq__
파이썬에서는 어떻게 처리되며 어떤 순서로 처리됩니까?
a == b
그것은 일반적으로 이해되지만, 항상 경우, 그 a == b
발동 할 a.__eq__(b)
, 또는 type(a).__eq__(a, b)
.
명시 적으로 평가 순서는 다음과 같습니다.
- 경우
b
의 유형의 엄격한 서브 (아니라 동일한 유형) 인 a
S 형 '및를 가지고 __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 레벨에서 처리됩니다.
여기서 우리는 두 개의 다른 코드 비트를 볼 필요가 있습니다. 즉, __eq__
class의 객체에 대한 기본값과 기본값 을 사용하는지 아니면 사용자 정의를 사용하는지에 관계없이 메서드 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
.
그러면 C 정의를 tp_richcompare
위해 생성 된 함수 "object"
가에 의해 호출되는 do_richcompare
것을 볼 수 있으므로 좀 더 자세히 살펴 보겠습니다.
이 함수의 첫 번째 검사는 비교되는 개체의 조건에 대한 것입니다.
- 있다 없다 같은 종류지만,
- 두 번째 유형은 첫 번째 유형의 하위 클래스이고
- 두 번째 유형에는
__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;
결론
비교에서 우리는 먼저 비교의 하위 클래스 구현을 존중합니다.
그런 다음 첫 번째 객체의 구현과 비교를 시도하고 호출되지 않은 경우 두 번째 객체와 비교를 시도합니다.
마지막으로 동일성 비교를 위해 동일성 테스트를 사용합니다.