在Python中,为什么/何时 `x==y` 会调用 `y.__eq__(x)`?
在Python中,为什么/何时 `x==y` 会调用 `y.__eq__(x)`?
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
编辑:从Mark Dickinson的答案和评论中可以看出:
- 富比较覆盖了
__cmp__
__eq__
是它自己的__rop__
到它的__op__
(__lt__
、__ge__
等类似)- 如果左对象是内置类或新式类,并且右对象是它的子类,则在左对象的
__op__
之前尝试右对象的__rop__
。
这解释了TestStrCmp
示例中的行为。 TestStrCmp
是str
的子类,但没有实现自己的__eq__
,因此在两种情况下都优先调用str
的__eq__
(即因为规则1而调用b.__eq__(tsc)
作为__rop__
)。
在TestStrEq
示例中,两个实例都调用tse.__eq__
,因为TestStrEq
是str
的子类,因此它的方法优先调用。
在TestEq示例中,TestEq实现了__eq__,而int没有,因此__eq__被调用了两次(规则1)。
但是我仍然不理解关于TestCmp的第一个示例。tc不是int的子类,因此根据我所知道的,应该调用1.__cmp__(tc),但是却没有被调用。
你忽略了通常行为的一个关键异常:当右操作数是左操作数所属类的子类的实例时,首先调用右操作数的特殊方法。请参阅以下文档: http://docs.python.org/reference/datamodel.html#coercion-rules ,特别是以下两段:对于对象x和y,首先尝试x.__op__(y)。 如果未实现或返回NotImplemented,则尝试y.__rop__(x)。 如果这也未实现或返回NotImplemented,则会引发TypeError异常。但请参见以下异常:前一项的异常:如果左操作数是内置类型或新式类的实例,并且右操作数是该类型或类的适当子类的实例并覆盖基础的__rop __()方法,则首先尝试右操作数的__rop__()方法,然后尝试左操作数的__op__()方法。