Skip to content Skip to sidebar Skip to footer

Python - Calling Ancestor Methods When Multiple Inheritance Is Involved

Edit: I'm using Python 3 (some people asked). I think this is just a syntax question, but I want to be sure there's nothing I'm missing. Notice the syntax difference in how Foo an

Solution 1:

  1. You should be using new-style classes. If this is Python 3, you are; if you are using Python 2, you should inherit from object (or some other new-style class).
  2. The usual way to invoke ancestor methods is using super. Read about it in the standard docs, and the other excellent articles on how it operates. It is never recommended to invoke the methods in the way you are doing because (a) it will be fragile in the face of further inheritance; and (b) you increase the maintenance effort by hardcoding references to classes.

Update: Here is an example showing how to use super to achieve this: http://ideone.com/u3si2

Also look at: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/

Update 2: Here's a little library for python 2 that adds a __class__ variable and a no-args super to every method to avoid hardcoding the current name: https://github.com/marcintustin/superfixer

Solution 2:

They aren't the same. X() creates an object of class X. When you do X().someMethod() you create a new object and then call the method on that object, not on self. X.someMethod(self) is what you want, since that calls the inherited method on the same object.

You will see the difference if your method actually does anything to the self object. For instance, if you put self.blah = 8 into your method, then after X.someMethod(self) the object you call it on will have the blah attribute set, but after X().someMethod() it will not. (Instead, you will have created a new object, set blah on that, and then thrown away that new object without using it, leaving the original object untouched.)

Here is a simple example modifying your code:

>>>classX:......defsome_method(self):...print("X.some_method called on", self)......classY:......defsome_method(self):...print("Y.some_method called on", self)......classFoo(X,Y):......defsome_method(self):...        X().some_method()...        Y().some_method()...print("Foo.some_method called on", self)......classBar(X,Y):......defsome_method(self):...        X.some_method(self)...        Y.some_method(self)...print("Bar.some_method called on", self)>>>Foo().some_method()
('X.some_method called on', <__main__.X instance at 0x0142F3C8>)
('Y.some_method called on', <__main__.Y instance at 0x0142F3C8>)
('Foo.some_method called on', <__main__.Foo instance at 0x0142F3A0>)
>>>Bar().some_method()
('X.some_method called on', <__main__.Bar instance at 0x0142F3C8>)
('Y.some_method called on', <__main__.Bar instance at 0x0142F3C8>)
('Bar.some_method called on', <__main__.Bar instance at 0x0142F3C8>)

Note that when I use Foo, the objects printed are not the same; one is an X instance, one is a Y instance, and the last is the original Foo instance that I called the method on. When Bar is used, it is the same object in each method call.

(You can also use super in some cases to avoid naming the base classes explicitly; e.g., super(Foo, self).someMethod() or in Python 3 just super().someMethod(). However, if you have a need to directly call inherited methods from two base classes, super might not be a good fit. It is generally aimed at cases where each method calls super just once, passing control to the next version of the method in the inheritance chain, which will then pass it along to the next, etc.)

Post a Comment for "Python - Calling Ancestor Methods When Multiple Inheritance Is Involved"