В python 2.7.6 предположим, что у меня есть класс, который определяет __eq__
и подкласс
его:
>>> class A(object):
... def __eq__(self,other):
... print self.__class__,other.__class__
... return True
...
>>> class B(A):
... pass
...
Теперь я создаю объект каждого класса и хочу сравнить его:
>>> a = A()
>>> b = B()
>>> a==b
Результат:
<class '__main__.B'> <class '__main__.A'>
Это показывает, что интерпретатор вызывает b.__eq__(a)
вместо a.__eq__(b)
как
ожидается.
documentation состояния (выделено мной):
Для объектов
x
иy
проверяется перваяx.__op__(y)
. Если это не реализовано или возвращаетNotImplemented
, проверяетсяy.__rop__(x)
. Если это также не реализовано или возвращаетNotImplemented
, возникает исключениеTypeError
. Но см. Следующее исключение:Исключение к предыдущему элементу: если левый операнд является экземпляром встроенного типа или класса нового стиля, а правый операнд является экземпляром соответствующего подкласса этого типа или класса и переопределяет метод оснований
__rop__()
, метод правых операндов__rop__()
проверяется перед левым операндом__op__()
.Это делается для того, чтобы подкласс мог полностью переопределить двоичные операторы. В противном случае метод левых операндов
__op__()
всегда будет принимать правый операнд: когда ожидается экземпляр данного класса, всегда допустим экземпляр подкласса этого класса.
Поскольку подкласс B
не переопределяет оператор __eq__
, не должен a.__eq__(b)
вызывать вместо b.__eq__(a)
? Является ли это ожидаемым поведением или ошибкой? Это противоречит документации, когда я ее читал: я неправильно истолковал документацию или пропустил что-то еще?
Некоторые связанные вопросы:
-
Этот ответ цитирует приведенную выше документацию. В этом случае последний вопрос включал сравнение объекта встроенного типа (1) и экземпляра нового стиля. Здесь я специально сравниваю экземпляр родительского класса с экземпляром подкласса, который не переопределяет метод
rop()
его parent (в этом случае__eq__
имеет значениеop()
иrop()
).В этом случае python фактически вызывает
b.__eq__(a)
вместоa.__eq__(b)
, хотя классB
явно не переопределяетA
.