【发布时间】:2021-06-02 14:55:00
【问题描述】:
例如,假设代码库包含以下类。实例代表可以相乘的复数:
class Complex:
def __init__(self, re, im):
self.re, self.im = re, im
def __mul__(lhs, rhs):
if isinstance(rhs, Complex): return Complex(...)
return NotImplemented
assert type(Complex(0, 0) * Complex(0, 0)) is Complex
实数是复数的特例,因此代码库还包含了它们的子类:
class Real(Complex):
def __init__(self, re):
self.re, self.im = re, 0
def __mul__(lhs, rhs):
if isinstance(rhs, Real): return Real(...)
if isinstance(rhs, Complex): return Complex(...)
return NotImplemented
def __rmul__(rhs, lhs):
if isinstance(lhs, Complex): return Complex(...)
return NotImplemented
assert type(Real(0) * Real(0)) is Real
assert type(Real(0) * Complex(0, 0)) is Complex
assert type(Complex(0, 0) * Real(0)) is Complex
我相信以上都是惯用的 Python,而且一切正常。现在假设我想在现有代码中添加一个虚数类。 Imaginary 是Complex 的子类和Real 的兄弟类:
class Imaginary(Complex):
def __init__(self, im):
self.re, self.im = 0, im
def __mul__(lhs, rhs):
if isinstance(rhs, Imaginary): return Real(...)
if isinstance(rhs, Real): return Imaginary(...)
if isinstance(rhs, Complex): return Complex(...)
return NotImplemented
def __rmul__(rhs, lhs):
if isinstance(lhs, Real): return Imaginary(...)
if isinstance(lhs, Complex): return Complex(...)
return NotImplemented
assert type(Imaginary(0) * Imaginary(0)) is Real
assert type(Imaginary(0) * Real(0)) is Imaginary
assert type(Imaginary(0) * Complex(0, 0)) is Complex
assert type(Real(0) * Imaginary(0)) is Imaginary # AssertionError
assert type(Complex(0, 0) * Imaginary(0)) is Complex
不幸的是,其中一个断言失败了。 type(Real(0) * Imaginary(0)) 是 Complex 而不是 Imaginary,因为 Python 通过调用 Real.__mul__ 而不是 Imaginary.__rmul__ 来执行乘法运算。
有没有办法写Imaginary,让重载的操作符都按预期工作,而不需要修改Complex或Real?
或者应该以不同的方式编写 Complex 和 Real 以使其能够正常工作(不需要他们了解 Imaginary)?
【问题讨论】:
-
这种听起来像Circle-ellipse problem。
-
对不起,它会先打电话给 LHS
__mul__...stackoverflow.com/questions/5181320/…
标签: python inheritance operator-overloading subclass