If I have a class B
, I can add support for subtracting two instances of B
and, for debugging purposes, return a string giving the types of the values being subtracted:
class B:
def __sub__(lhs, rhs):
if isinstance(rhs, B): return 'B() - B()'
return NotImplemented
print(B() - B()) # B() - B()
If I then add a class C
derived from B
, I can extend that support:
class C(B):
def __sub__(lhs, rhs):
if isinstance(rhs, C): return 'C() - C()'
if isinstance(rhs, B): return 'C() - B()'
return NotImplemented
def __rsub__(rhs, lhs):
if isinstance(lhs, B): return 'B() - C()'
return NotImplemented
print(C() - C()) # C() - C()
print(C() - B()) # C() - B()
print(B() - C()) # B() - C()
Notice that B() - C()
works correctly. C
is a subclass of B
, so Python calls C
's __radd__
method instead of B
's __add__
method.
Now if I add a class D
, also derived from B
, and try to extend the support further:
class D(B):
def __sub__(lhs, rhs):
if isinstance(rhs, D): return 'D() - D()'
if isinstance(rhs, C): return 'D() - C()'
if isinstance(rhs, B): return 'D() - B()'
return NotImplemented
def __rsub__(rhs, lhs):
if isinstance(lhs, C): return 'C() - D()'
if isinstance(lhs, B): return 'B() - D()'
return NotImplemented
print(D() - D()) # D() - D()
print(D() - C()) # D() - C()
print(D() - B()) # D() - B()
print(C() - D()) # C() - B() !!!
print(B() - D()) # B() - D()
Notice that C() - D()
returns the wrong types. Neither is a subclass of the other, so Python calls C
's __add__
method instead of D
's __radd__
method (which would return the correct value).
Is there a way to make this work? Moreover, is there an established pattern to follow when implementing operator overloads - so they work properly when new subclasses are added, without modifying existing classes?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…