I am new to Python, I am coming from C++ so I suspect my way of thinking is "tainted" by my preconceived notions. I will explain what I am trying to do and the issue I am facing, but please be aware that the code below is an "artificial" little example that reproduces my issue.
Say that at some point I have this scenario, where B only overrides A.plot_and_clear() as that is all I need from B:
class A:
def __init__(self, x, y):
self.x = x
self.y = y
def clear(self):
print("clear A start")
self.x = 0
self.y = 0
print("clear A end")
def plot(self):
print("plot A start")
print(str(self.x))
print(str(self.y))
print("plot A end")
def plot_and_clear(self):
print("plot & clear A start")
self.plot()
self.clear()
print("plot & clear A end")
class B(A):
def __init__(self, x, y, z):
super().__init__(x, y)
self.z = z
def plot_and_clear(self):
print("plot & clear B BAD start")
super().plot_and_clear()
print(str(self.z))
self.z = 0
print("plot & clear B BAD end")
def main():
myObject = B(1, 2, 3)
myObject.plot_and_clea()
main()
In this case the output is exactly what I would expect and goes as follows:
plot & clear B start
plot & clear A start
plot A start
1
2
plot A end
clear A start
clear A end
plot & clear A end
3
plot & clear B end
Later on I realize that I also need to override A.plot() with B.plot(), with all the rest remaining the same like so:
class A:
def __init__(self, x, y):
self.x = x
self.y = y
def clear(self):
print("clear A start")
self.x = 0
self.y = 0
print("clear A end")
def plot(self):
print("plot A start")
print(str(self.x))
print(str(self.y))
print("plot A end")
def plot_and_clear(self):
print("plot & clear A start")
self.plot()
self.clear()
print("plot & clear A end")
class B(A):
def __init__(self, x, y, z):
super().__init__(x, y)
self.z = z
def plot(self):
print("plot B start")
super().plot()
print(str(self.z))
print("plot B end")
def plot_and_clear(self):
print("plot & clear B BAD start")
super().plot_and_clear()
print(str(self.z))
self.z = 0
print("plot & clear B BAD end")
def main():
myObject = B(1, 2, 3)
myObject.plot_and_clea()
main()
Now if we run the same main, the output is changed and erroneous and goes like this:
plot & clear B start
plot & clear A start
plot B start
plot A start
1
2
plot A end
3
plot B end
clear A start
clear A end
plot & clear A end
3
plot & clear B end
This is because now, the super().plot_and_clear() from B.plot_and_clear() calls B.plot() instead of A.plot(). The result of this is that by simply adding a function I have broken the previously good behavior of B.plot_and_clear(), which is puzzling to say the least.
I understand this is due to how the MRO works in python, which as it seems, is completely flipped compared to c++. Now wheter or not we know the exact reason why this happens I would still argue that the behavior is not desirable and there should be a way to prevent it, either by choosing some "safe" code structure or with some other language constructs.
Any idea of how I can either work "around" or "along" this aspect of the language?
Thank you very much.