看起来子类被认为“覆盖”超类行为,即使它所做的只是继承超类行为。这在__eq__
案例因为__eq__
是它自己的反射,但是如果使用不同的运算符,你可以更清楚地看到它,例如__lt__
and __gt__
,这是彼此的反射:
class A(object):
def __gt__(self,other):
print "GT", self.__class__, other.__class__
def __lt__(self,other):
print "LT", self.__class__, other.__class__
class B(A):
pass
Then:
>>> A() > B()
LT <class '__main__.B'> <class '__main__.A'>
注意A.__gt__
没有被叫到;反而,B.__lt__
被称为。
The Python 3 文档 https://docs.python.org/3/reference/datamodel.html#object.__ror__是说明性的,因为它用不同的词语陈述了规则,这些词语在技术上更准确(强调是添加的):
如果右操作数的类型是左操作数类型的子类并且该子类provides该操作的反射方法,该方法将在左操作数的非反射方法之前被调用。这种行为允许子类覆盖其祖先的操作。
子类确实“提供”了反射方法,它只是通过继承提供它。如果您实际上删除了子类中反射的方法行为(通过返回 NotImplemented),则超类方法将被正确调用(在子类方法之后):
class A(object):
def __gt__(self,other):
print "GT", self.__class__, other.__class__
def __lt__(self,other):
print "LT", self.__class__, other.__class__
class B(A):
def __lt__(self, other):
print "LT", self.__class__, other.__class__
return NotImplemented
>>> A() > B()
LT <class '__main__.B'> <class '__main__.A'>
GT <class '__main__.A'> <class '__main__.B'>
所以基本上这似乎是一个文档错误。应该说子类反射的方法是always首先尝试(对于比较运算符),无论子类是否显式覆盖超类实现。 (不过,正如 Mark Dickinson 在评论中指出的那样,它仅适用于比较运算符,不适用于数学运算符对,例如__add__
/__radd__
.)
在实践中,这不太重要,因为您唯一注意到它是当子类doesn't覆盖超类。但在这种情况下,子类的行为根据定义与超类的行为相同,因此调用哪一个并不重要(除非您正在做一些危险的事情,例如从比较方法中改变对象,在这种情况下无论如何你应该保持警惕)。