Consider:
class X:
def some_method(self):
print("X.some_method called")
class Y:
def some_method(self):
print("Y.some_method called")
class Foo(X,Y):
def some_method(self):
super().some_method()
# plus some Foo-specific work to be done here
foo_instance = Foo()
foo_instance.some_method()
Output:
X.some_method called
Switching the class declaration of Foo to instead be:
class Foo(Y,X):
Alters the output to:
Y.some_method called
If I want both ancestor methods to be called I could alter Foo’s implementation as:
def some_method(self):
X().some_method()
Y().some_method()
# plus some Foo-specific work to be done here
This leads to my question. Is there any uber secret way to cause Python to invoke the method on all ancestors without me doing so explicitly like the code, such as (I’m making up the all_ancestors keyword here – does such a thing actually exist?):
def some_method(self):
all_ancestors().some_method()
# plus some Foo-specific work to be done here
with an expected output of:
X.some_method called
Y.some_method called
No, there is no secret way to do that. As I mentioned in your other question, the usual way to do this is not to call all ancestor methods from the single descendant class. Instead, each class should use
superto call just one ancestor method, namely the next one up the inheritance chain. If every class in the tree does this (except the topmost base class), then all methods will get called in order. In other words, Foo should usesuper(), which will callX‘s method; and thenXshould also usesuper(), which will callY‘s method.To make this work right, it is usually best to have a single topmost class in the inheritance tree. In your example this would be a class that is the base of both X and Y. You need such a class to serve as a final stop to the sequence of
supercalling; this base class should not call super. If you just keep callingsupereverywhere, eventually it will try to call up to the baseobjectclass, and then fail becauseobjectdoesn’t provide the method you’re trying to call.