В документации Python четко указано, что x==y
вызывает x.__eq__(y)
. Однако кажется, что во многих случаях верно обратное. Где задокументировано, когда и почему это происходит, и как я могу точно определить, будут ли вызываться методы __cmp__
или __eq__
моего объекта.
Изменить: Просто чтобы уточнить, я знаю, что __eq__
вызывается в предпочтении к __cmp__
, но мне не ясно, почему y.__eq__(x)
вызывается в предпочтении к x.__eq__(y)
, когда последнее - это то, что произойдет в состоянии документов.
>>> class TestCmp(object):
... def __cmp__(self, other):
... print "__cmp__ got called"
... return 0
...
>>> class TestEq(object):
... def __eq__(self, other):
... print "__eq__ got called"
... return True
...
>>> tc = TestCmp()
>>> te = TestEq()
>>>
>>> 1 == tc
__cmp__ got called
True
>>> tc == 1
__cmp__ got called
True
>>>
>>> 1 == te
__eq__ got called
True
>>> te == 1
__eq__ got called
True
>>>
>>> class TestStrCmp(str):
... def __new__(cls, value):
... return str.__new__(cls, value)
...
... def __cmp__(self, other):
... print "__cmp__ got called"
... return 0
...
>>> class TestStrEq(str):
... def __new__(cls, value):
... return str.__new__(cls, value)
...
... def __eq__(self, other):
... print "__eq__ got called"
... return True
...
>>> tsc = TestStrCmp("a")
>>> tse = TestStrEq("a")
>>>
>>> "b" == tsc
False
>>> tsc == "b"
False
>>>
>>> "b" == tse
__eq__ got called
True
>>> tse == "b"
__eq__ got called
True
Изменить: из ответа и комментария Марка Дикинсона может показаться, что:
- Расширенное сравнение переопределяет
__cmp__
__eq__
является собственным__rop__
для своего__op__
(и аналогично для__lt__
,__ge__
и т. д.)- Если левый объект является встроенным классом или классом нового стиля, а правый является его подклассом, то
__rop__
правого объекта пробуется перед__op__
левого объекта.
Это объясняет поведение в примерахTestStrCmp
. TestStrCmp
является подклассом str
, но не реализует свой собственный __eq__
, поэтому __eq__
из str
имеет приоритет в обоих случаях (т.е. tsc == "b"
вызывает b.__eq__(tsc)
как __rop__
из-за правила 1).
В примерах TestStrEq
tse.__eq__
вызывается в обоих случаях, потому что TestStrEq
является подклассом str
и поэтому вызывается предпочтительно.
В примерах TestEq
TestEq
реализует __eq__
, а int
нет, поэтому __eq__
вызывается оба раза (правило 1).
Но я до сих пор не понимаю самого первого примера с TestCmp
. tc
не является подклассом int
, поэтому следует вызывать AFAICT 1.__cmp__(tc)
, но это не так.