2016-12-09 2 views
1

Следующий код работает с Python 2.7:Почему `int .__ eq __ (другое)` рабочее сравнение?

>>> class Derived(int): 
...  def __eq__(self, other): 
...   return int.__eq__(other) 
... 
>>> Derived(12) == 12.0 
True 
>>> Derived(12) == 13 
False 

Я не понимаю, почему это работает, при условии, что атрибут self явно не дано int.__eq__() вызова метода.

[EDIT]

ответы до сих пор предложил, что речь идет о возвращении NotImplemented по self.__eq__(other) и, таким образом, вызывая other.__eq__(self). Тогда Derived(12) == Derived(12) я ожидаю, что инфинитив рекурсию, которая не так:

>>> Derived(12) == Derived(12) 
True 

ответ

4

Это работает, потому что int.__eq__(<something>) возвращается NotImplemented и когда это произойдет, это приводит к вызову other.__eq__(self) и это то, что возвращается True и False здесь.

Демо:

class Derived(int): 
    def __eq__(self, other): 
     print self, other 
     print int.__eq__(other) 
     print other.__eq__(self) 
     return int.__eq__(other) 

>>> Derived(12) == 12.0 
12 12.0 
NotImplemented 
True 
True 
>>> Derived(12) == 13.0 
12 13.0 
NotImplemented 
False 
False 

От NotImplemented Docs «s:

Особое значение, которое должно быть возвращено бинарными специальными методами (например __eq__(), __lt__(), __add__(), __rsub__(), и т. д.) до указывают, что операция не выполняется в отношении другой тип; могут быть возвращены двоичными специальными методами in-place (например, __imul__(), __iand__() и т. д.) с той же целью. Его истинное значение имеет значение .

Примечание При NotImplemented возвращается, интерпретатор будет пытаться отраженная операцию на другом типе, или какой-либо другой резервный, в зависимости от оператора. Если все предпринятые операции возвращают NotImplemented, интерпретатор поднимет соответствующее исключение.


Что происходит, когда оба __eq__ возвращение NotImplemented?

Поведение отличается в Python 2 и 3.

В Python 2 она падает обратно в __cmp__ метод первого и целые числа имеют __cmp__ method in Python 2. Он удален в Python 3.

В соответствии с Python 2 Docs, если ничего не найдено, что в конечном итоге возвращается к сравнению идентичности:

Если нет __cmp__(), __eq__() или __ne__() операции определяются, класс экземпляров сравниваются по идентификатору объекта («адрес»)

class Derived(int): 
    def __eq__(self, other): 
     print ("Inside __eq__") 
     return NotImplemented 

    def __cmp__(self, other): 
     print ("Inside __cmp__ finally") 
     return True 

>>> Derived(12) == Derived(12) 
Inside __eq__ 
Inside __eq__ 
Inside __cmp__ finally 
False 

Не давайте определим класс без каких-либо методом, определенным:

class Derived(object): 
    pass 

>>> Derived() == Derived() 
False 
>>> d = Derived() 
>>> d == d # Same objects. 
True 

У Python 3 больше нет метода __cmp__, но он, похоже, теперь возвращается к идентичности. И, похоже, это не документировано.

# Python 3.5 
>>> Derived() == Derived() 
False 
>>> d = Derived() 
>>> d == d 
True 
0

В Python 2.7, если вы звоните int.__eq__ он всегда возвращает NotImplemented. Пример:

>>> int.__eq__(12.0) 
NotImplemented 

При использовании оператора == он будет пытаться запустить метод __eq__ на левый аргумент, и если он получает NotImplemented он возвращает результат метода __eq__ от аргумента справа.

В вашем примере для Derived(12) == 12.0, переводчик сначала пробует Derived(12).__eq__(12.0) и получает NotImplemented. Затем он запускает метод __eq__ на float номер 12.0 и получает True.

В случае Вашего Derived(12) == Derived(12) Например, что, скорее всего, происходит то, что так как оба объекта возвращают NotImplemented для их __eq__ методов, а с Derived наследуется от int, интерпретатор возвращается к с помощью встроенного поведения cmp для int (в соответствии с this answer , что связано с другим ответом на ваш вопрос).

Вот пример, который иллюстрирует ваш случай:

class Derived(int): 
    def __eq__(self, other): 
     print 'Doing eq' 
     return NotImplemented 
    def __cmp__(self, other): 
     print 'doing cmp' 
     return 0 # contrived example - don't do this 

>>> Derived(12) == Derived(12) 
doing eq 
doing eq 
doing cmp 
True 
+0

Edited принять во внимание все аргументы для 'междунар .__ eq__' – Billy

+0

Обновлен вопрос о включении' Derived (12) == Производная (12) 'случай – abukaj

1

При смешивании поплавка с целым типом, нет никакой пользы равномерной подхода. https://github.com/python/cpython/blob/2.7/Objects/floatobject.c#L401-L417

P.S. How int() object using "==" operator without __eq__() method in python2?

+0

О, давай, 12 даже не перетекание половинной прецизионный поплавок. Он отлично преобразуется в двойное. – abukaj

Смежные вопросы