В документах Python четко указано, что x==y
вызывает x.__eq__(y)
. Однако кажется, что при многих обстоятельствах верно обратное. Где это описано, когда и почему это происходит, и как я могу точно определить, будут ли вызовы методы моего объекта __cmp__
или __eq__
.
Изменить: просто чтобы уточнить, я знаю, что __eq__
вызывается в preferecne для __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__
и т.д.) - Если левый объект является классом builtin или new-style, а правым является его подкласс, правый объект
__rop__
проверяется перед левым объектом__op__
Это объясняет поведение в примерах TestStrCmp
. TestStrCmp
является подклассом str
, но не реализует его собственный __eq__
, поэтому __eq__
of 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)
должен вызываться, но это не так.