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 and Bar are implemented. They achieve the same thing and I want to make sure they're really doing the same thing. The output suggests that there are just two ways to do the same thing. Is that the case?
Code:
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):
X().some_method()
Y().some_method()
print("Foo.some_method called")
class Bar(X,Y):
def some_method(self):
X.some_method(self)
Y.some_method(self)
print("Bar.some_method called")
print("=== Fun with Foo ===")
foo_instance = Foo()
foo_instance.some_method()
print("=== Fun with Bar ===")
bar_instance = Bar()
bar_instance.some_method()
Output:
=== Fun with Foo ===
X.some_method called
Y.some_method called
Foo.some_method called
=== Fun with Bar ===
X.some_method called
Y.some_method called
Bar.some_method called
PS - Hopefully it goes without saying but this is just an abstract example, let's not worry about why I'd want to call some_method on both ancestors, I'm just trying to understand the syntax and mechanics of the language here. Thanks all!
They aren't the same.
X()
creates an object of classX
. When you doX().someMethod()
you create a new object and then call the method on that object, not onself
.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 putself.blah = 8
into your method, then afterX.someMethod(self)
the object you call it on will have theblah
attribute set, but afterX().someMethod()
it will not. (Instead, you will have created a new object, setblah
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:
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. WhenBar
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 justsuper().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 callssuper
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.)object
(or some other new-style class).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/u3si2Also 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-argssuper
to every method to avoid hardcoding the current name: https://github.com/marcintustin/superfixer