This question already has answers here:
What does 'super' do in Python? - difference between super().__init__() and explicit superclass __init__()
(11 answers)
Closed 7 years ago.
Why is super() used?
Is there a difference between using Base.__init__ and super().__init__?
class Base(object):
def __init__(self):
print "Base created"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
ChildA()
ChildB()
super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.
Note that the syntax changed in Python 3.0: you can just say super().__init__() instead of super(ChildB, self).__init__() which IMO is quite a bit nicer. The standard docs also refer to a guide to using super() which is quite explanatory.
I'm trying to understand super()
The reason we use super is so that child classes that may be using cooperative multiple inheritance will call the correct next parent class function in the Method Resolution Order (MRO).
In Python 3, we can call it like this:
class ChildB(Base):
def __init__(self):
super().__init__()
In Python 2, we were required to call super like this with the defining class's name and self, but we'll avoid this from now on because it's redundant, slower (due to the name lookups), and more verbose (so update your Python if you haven't already!):
super(ChildB, self).__init__()
Without super, you are limited in your ability to use multiple inheritance because you hard-wire the next parent's call:
Base.__init__(self) # Avoid this.
I further explain below.
"What difference is there actually in this code?:"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super().__init__()
The primary difference in this code is that in ChildB you get a layer of indirection in the __init__ with super, which uses the class in which it is defined to determine the next class's __init__ to look up in the MRO.
I illustrate this difference in an answer at the canonical question, How to use 'super' in Python?, which demonstrates dependency injection and cooperative multiple inheritance.
If Python didn't have super
Here's code that's actually closely equivalent to super (how it's implemented in C, minus some checking and fallback behavior, and translated to Python):
class ChildB(Base):
def __init__(self):
mro = type(self).mro()
check_next = mro.index(ChildB) + 1 # next after *this* class.
while check_next < len(mro):
next_class = mro[check_next]
if '__init__' in next_class.__dict__:
next_class.__init__(self)
break
check_next += 1
Written a little more like native Python:
class ChildB(Base):
def __init__(self):
mro = type(self).mro()
for next_class in mro[mro.index(ChildB) + 1:]: # slice to end
if hasattr(next_class, '__init__'):
next_class.__init__(self)
break
If we didn't have the super object, we'd have to write this manual code everywhere (or recreate it!) to ensure that we call the proper next method in the Method Resolution Order!
How does super do this in Python 3 without being told explicitly which class and instance from the method it was called from?
It gets the calling stack frame, and finds the class (implicitly stored as a local free variable, __class__, making the calling function a closure over the class) and the first argument to that function, which should be the instance or class that informs it which Method Resolution Order (MRO) to use.
Since it requires that first argument for the MRO, using super with static methods is impossible as they do not have access to the MRO of the class from which they are called.
Criticisms of other answers:
super() lets you avoid referring to the base class explicitly, which can be nice. . But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.
It's rather hand-wavey and doesn't tell us much, but the point of super is not to avoid writing the parent class. The point is to ensure that the next method in line in the method resolution order (MRO) is called. This becomes important in multiple inheritance.
I'll explain here.
class Base(object):
def __init__(self):
print("Base init'ed")
class ChildA(Base):
def __init__(self):
print("ChildA init'ed")
Base.__init__(self)
class ChildB(Base):
def __init__(self):
print("ChildB init'ed")
super().__init__()
And let's create a dependency that we want to be called after the Child:
class UserDependency(Base):
def __init__(self):
print("UserDependency init'ed")
super().__init__()
Now remember, ChildB uses super, ChildA does not:
class UserA(ChildA, UserDependency):
def __init__(self):
print("UserA init'ed")
super().__init__()
class UserB(ChildB, UserDependency):
def __init__(self):
print("UserB init'ed")
super().__init__()
And UserA does not call the UserDependency method:
>>> UserA()
UserA init'ed
ChildA init'ed
Base init'ed
<__main__.UserA object at 0x0000000003403BA8>
But UserB does in-fact call UserDependency because ChildB invokes super:
>>> UserB()
UserB init'ed
ChildB init'ed
UserDependency init'ed
Base init'ed
<__main__.UserB object at 0x0000000003403438>
Criticism for another answer
In no circumstance should you do the following, which another answer suggests, as you'll definitely get errors when you subclass ChildB:
super(self.__class__, self).__init__() # DON'T DO THIS! EVER.
(That answer is not clever or particularly interesting, but in spite of direct criticism in the comments and over 17 downvotes, the answerer persisted in suggesting it until a kind editor fixed his problem.)
Explanation: Using self.__class__ as a substitute for the class name in super() will lead to recursion. super lets us look up the next parent in the MRO (see the first section of this answer) for child classes. If you tell super we're in the child instance's method, it will then lookup the next method in line (probably this one) resulting in recursion, probably causing a logical failure (in the answerer's example, it does) or a RuntimeError when the recursion depth is exceeded.
>>> class Polygon(object):
... def __init__(self, id):
... self.id = id
...
>>> class Rectangle(Polygon):
... def __init__(self, id, width, height):
... super(self.__class__, self).__init__(id)
... self.shape = (width, height)
...
>>> class Square(Rectangle):
... pass
...
>>> Square('a', 10, 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'
Python 3's new super() calling method with no arguments fortunately allows us to sidestep this issue.
It's been noted that in Python 3.0+ you can use
super().__init__()
to make your call, which is concise and does not require you to reference the parent OR class names explicitly, which can be handy. I just want to add that for Python 2.7 or under, some people implement a name-insensitive behaviour by writing self.__class__ instead of the class name, i.e.
super(self.__class__, self).__init__() # DON'T DO THIS!
HOWEVER, this breaks calls to super for any classes that inherit from your class, where self.__class__ could return a child class. For example:
class Polygon(object):
def __init__(self, id):
self.id = id
class Rectangle(Polygon):
def __init__(self, id, width, height):
super(self.__class__, self).__init__(id)
self.shape = (width, height)
class Square(Rectangle):
pass
Here I have a class Square, which is a sub-class of Rectangle. Say I don't want to write a separate constructor for Square because the constructor for Rectangle is good enough, but for whatever reason I want to implement a Square so I can reimplement some other method.
When I create a Square using mSquare = Square('a', 10,10), Python calls the constructor for Rectangle because I haven't given Square its own constructor. However, in the constructor for Rectangle, the call super(self.__class__,self) is going to return the superclass of mSquare, so it calls the constructor for Rectangle again. This is how the infinite loop happens, as was mentioned by #S_C. In this case, when I run super(...).__init__() I am calling the constructor for Rectangle but since I give it no arguments, I will get an error.
Super has no side effects
Base = ChildB
Base()
works as expected
Base = ChildA
Base()
gets into infinite recursion.
Just a heads up... with Python 2.7, and I believe ever since super() was introduced in version 2.2, you can only call super() if one of the parents inherit from a class that eventually inherits object (new-style classes).
Personally, as for python 2.7 code, I'm going to continue using BaseClassName.__init__(self, args) until I actually get the advantage of using super().
There isn't, really. super() looks at the next class in the MRO (method resolution order, accessed with cls.__mro__) to call the methods. Just calling the base __init__ calls the base __init__. As it happens, the MRO has exactly one item-- the base. So you're really doing the exact same thing, but in a nicer way with super() (particularly if you get into multiple inheritance later).
The main difference is that ChildA.__init__ will unconditionally call Base.__init__ whereas ChildB.__init__ will call __init__ in whatever class happens to be ChildB ancestor in self's line of ancestors
(which may differ from what you expect).
If you add a ClassC that uses multiple inheritance:
class Mixin(Base):
def __init__(self):
print "Mixin stuff"
super(Mixin, self).__init__()
class ChildC(ChildB, Mixin): # Mixin is now between ChildB and Base
pass
ChildC()
help(ChildC) # shows that the Method Resolution Order is ChildC->ChildB->Mixin->Base
then Base is no longer the parent of ChildB for ChildC instances. Now super(ChildB, self) will point to Mixin if self is a ChildC instance.
You have inserted Mixin in between ChildB and Base. And you can take advantage of it with super()
So if you are designed your classes so that they can be used in a Cooperative Multiple Inheritance scenario, you use super because you don't really know who is going to be the ancestor at runtime.
The super considered super post and pycon 2015 accompanying video explain this pretty well.
Related
I looked at answers https://stackoverflow.com/a/33469090/11638153 and https://stackoverflow.com/a/27134600 but did not understand what is "indirection." To be specific, if I have classes like below, are there any drawbacks or advantages in hardcoding the parent class __init__(), as done in class Child1 (why do we need super() when one can explicitly write __init__() methods to invoke)?
class Base1:
def __init__(self):
print("Class Base1 init()")
class Base2:
def __init__(self):
print("Class Base2 init()")
class Child1(Base1, Base2):
def __init__(self):
print("Class Child1 init()")
Base1.__init__(self)
Base2.__init__(self)
class Child2(Base1, Base2):
def __init__(self):
print("Class Child2 init()")
super().__init__()
if __name__ == "__main__":
obj1 = Child1()
print("---")
obj2 = Child2()
Roughly, the difference is that ParentClass.__init__(self) always calls the specifically named class while super().__init__() makes a runtime computation to determine which class to call.
In many situations, the two ways give the same results. However, super() is much more powerful. It a multiple inheritance scenario, it can potentially call some class other than the parent of the current class. This article covers the latter scenario is detail.
For single inheritance, the reason to prefer super() is that that it read nicely and that it makes maintenance easier by computing the parent class.
For multiple inheritance, super() is the only straightforward way to access parent classes in the order of the MRO for the class of the calling instance. If those words don't mean anything to you, please look at the referenced article.
In your example code, Child1's design is very fragile. If its two base classes share some common base (and call their own parents' __init__ method inside of their own turn), that grandparent class might get initialized more than once, which would be bad if it's computationally costly, or has side effects. This is the "diamond pattern" of inheritance hierarchy that can be troublesome in many languages (like C++) that allow multiple inheritance.
Here's an example of the bad problem that can come up with explicit parent calls, and which super() is designed to fix:
class Grandparent:
def __init__(self):
print("Grandparent")
class Parent1(Grandparent):
def __init__(self):
print("Parent1")
Grandparent.__init__(self)
class Parent2(Grandparent):
def __init__(self):
print("Parent2")
Grandparent.__init__(self)
class Child(Parent1, Parent2):
def __init__(self):
print("Child")
Parent1.__init__(self)
Parent2.__init__(self)
c = Child() # this causes "Grandparent" to be printed twice!
Python's solution is to use super() which allows collaborative multiple inheritance. Each class must be set up to use it, including the intermediate base classes! Once you set everything up to use super, they'll call each other as necessary, and nothing will ever get called more than once.
class Grandparent:
def __init__(self):
print("Grandparent")
class Parent1(Grandparent):
def __init__(self):
print("Parent1")
super().__init__()
class Parent2(Grandparent):
def __init__(self):
print("Parent2")
super().__init__()
class Child(Parent1, Parent2):
def __init__(self):
print("Child")
super().__init__()
c = Child() # no extra "Grandparent" printout this time
In fact, every instance of multiple-inheritance in Python is a diamond shape, with the Grandparent class of object (if not something else). The object class has an __init__ method that takes no arguments (other than self) and does nothing.
It's important to note that the super().__init__ calls from the ParentX classes don't always go directly to Grandparent. When initializing an instance of Parent1 or Parent2, they will, but when instantiating an instance of Child, then Parent1.__init__'s call will go to Parent2.__init__, and only from there will Parent2's super call go to Grandparent.__init__.
Where a super call resolves to depends on the MRO (Method Resolution Order) of the instance the methods are being called on. A super call generally means "find this method in the next class in the MRO" relative to where it's called from. You can see the MRO of a class by calling SomeClass.mro(). For Child in my examples, it's: [Child, Parent1, Parent2, Grandparent, object]
According to Python docs super()
is useful for accessing inherited methods that have been overridden in
a class.
I understand that super refers to the parent class and it lets you access parent methods. My question is why do people always use super inside the init method of the child class? I have seen it everywhere. For example:
class Person:
def __init__(self, name):
self.name = name
class Employee(Person):
def __init__(self, **kwargs):
super().__init__(name=kwargs['name']) # Here super is being used
def first_letter(self):
return self.name[0]
e = Employee(name="John")
print(e.first_letter())
I can accomplish the same without super and without even an init method:
class Person:
def __init__(self, name):
self.name = name
class Employee(Person):
def first_letter(self):
return self.name[0]
e = Employee(name="John")
print(e.first_letter())
Are there drawbacks with the latter code? It looks so much cleanr to me. I don't even have to use the boilerplate **kwargs and kwargs['argument'] syntax.
I am using Python 3.8.
Edit: Here's another stackoverflow questions which has code from different people who are using super in the child's init method. I don't understand why. My best guess is there's something new in Python 3.8.
The child might want to do something different or more likely additional to what the super class does - in this case the child must have an __init__.
Calling super’s init means that you don’t have to copy/paste (with all the implications for maintenance) that init in the child’s class, which otherwise would be needed if you wanted some additional code in the child init.
But note there are complications about using super’s init if you use multiple inheritance (e.g. which super gets called) and this needs care. Personally I avoid multiple inheritance and keep inheritance to aminimum anyway - it’s easy to get tempted into creating multiple levels of inheritance/class hierarchy but my experience is that a ‘keep it simple’ approach is usually much better.
The potential drawback to the latter code is that there is no __init__ method within the Employee class. Since there is none, the __init__ method of the parent class is called. However, as soon as an __init__ method is added to the Employee class (maybe there's some Employee-specific attribute that needs to be initialized, like an id_number) then the __init__ method of the parent class is overridden and not called (unless super.__init__() is called) and then an Employee will not have a name attribute.
The correct way to use super here is for both methods to use super. You cannot assume that Person is the last (or at least, next-to-last, before object) class in the MRO.
class Person:
def __init__(self, name, **kwargs):
super().__init__(**kwargs)
self.name = name
class Employee(Person):
# Optional, since Employee.__init__ does nothing
# except pass the exact same arguments "upstream"
def __init__(self, **kwargs):
super().__init__(**kwargs)
def first_letter(self):
return self.name[0]
Consider a class definition like
class Bar:
...
class Foo(Person, Bar):
...
The MRO for Foo looks like [Foo, Person, Bar, object]; the call to super().__init__ inside Person.__init__ would call Bar.__init__, not object.__init__, and Person has no way of knowing if values in **kwargs are meant for Bar, so it must pass them on.
This question already has answers here:
What does 'super' do in Python? - difference between super().__init__() and explicit superclass __init__()
(11 answers)
Closed 7 years ago.
Why is super() used?
Is there a difference between using Base.__init__ and super().__init__?
class Base(object):
def __init__(self):
print "Base created"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
ChildA()
ChildB()
super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.
Note that the syntax changed in Python 3.0: you can just say super().__init__() instead of super(ChildB, self).__init__() which IMO is quite a bit nicer. The standard docs also refer to a guide to using super() which is quite explanatory.
I'm trying to understand super()
The reason we use super is so that child classes that may be using cooperative multiple inheritance will call the correct next parent class function in the Method Resolution Order (MRO).
In Python 3, we can call it like this:
class ChildB(Base):
def __init__(self):
super().__init__()
In Python 2, we were required to call super like this with the defining class's name and self, but we'll avoid this from now on because it's redundant, slower (due to the name lookups), and more verbose (so update your Python if you haven't already!):
super(ChildB, self).__init__()
Without super, you are limited in your ability to use multiple inheritance because you hard-wire the next parent's call:
Base.__init__(self) # Avoid this.
I further explain below.
"What difference is there actually in this code?:"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super().__init__()
The primary difference in this code is that in ChildB you get a layer of indirection in the __init__ with super, which uses the class in which it is defined to determine the next class's __init__ to look up in the MRO.
I illustrate this difference in an answer at the canonical question, How to use 'super' in Python?, which demonstrates dependency injection and cooperative multiple inheritance.
If Python didn't have super
Here's code that's actually closely equivalent to super (how it's implemented in C, minus some checking and fallback behavior, and translated to Python):
class ChildB(Base):
def __init__(self):
mro = type(self).mro()
check_next = mro.index(ChildB) + 1 # next after *this* class.
while check_next < len(mro):
next_class = mro[check_next]
if '__init__' in next_class.__dict__:
next_class.__init__(self)
break
check_next += 1
Written a little more like native Python:
class ChildB(Base):
def __init__(self):
mro = type(self).mro()
for next_class in mro[mro.index(ChildB) + 1:]: # slice to end
if hasattr(next_class, '__init__'):
next_class.__init__(self)
break
If we didn't have the super object, we'd have to write this manual code everywhere (or recreate it!) to ensure that we call the proper next method in the Method Resolution Order!
How does super do this in Python 3 without being told explicitly which class and instance from the method it was called from?
It gets the calling stack frame, and finds the class (implicitly stored as a local free variable, __class__, making the calling function a closure over the class) and the first argument to that function, which should be the instance or class that informs it which Method Resolution Order (MRO) to use.
Since it requires that first argument for the MRO, using super with static methods is impossible as they do not have access to the MRO of the class from which they are called.
Criticisms of other answers:
super() lets you avoid referring to the base class explicitly, which can be nice. . But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.
It's rather hand-wavey and doesn't tell us much, but the point of super is not to avoid writing the parent class. The point is to ensure that the next method in line in the method resolution order (MRO) is called. This becomes important in multiple inheritance.
I'll explain here.
class Base(object):
def __init__(self):
print("Base init'ed")
class ChildA(Base):
def __init__(self):
print("ChildA init'ed")
Base.__init__(self)
class ChildB(Base):
def __init__(self):
print("ChildB init'ed")
super().__init__()
And let's create a dependency that we want to be called after the Child:
class UserDependency(Base):
def __init__(self):
print("UserDependency init'ed")
super().__init__()
Now remember, ChildB uses super, ChildA does not:
class UserA(ChildA, UserDependency):
def __init__(self):
print("UserA init'ed")
super().__init__()
class UserB(ChildB, UserDependency):
def __init__(self):
print("UserB init'ed")
super().__init__()
And UserA does not call the UserDependency method:
>>> UserA()
UserA init'ed
ChildA init'ed
Base init'ed
<__main__.UserA object at 0x0000000003403BA8>
But UserB does in-fact call UserDependency because ChildB invokes super:
>>> UserB()
UserB init'ed
ChildB init'ed
UserDependency init'ed
Base init'ed
<__main__.UserB object at 0x0000000003403438>
Criticism for another answer
In no circumstance should you do the following, which another answer suggests, as you'll definitely get errors when you subclass ChildB:
super(self.__class__, self).__init__() # DON'T DO THIS! EVER.
(That answer is not clever or particularly interesting, but in spite of direct criticism in the comments and over 17 downvotes, the answerer persisted in suggesting it until a kind editor fixed his problem.)
Explanation: Using self.__class__ as a substitute for the class name in super() will lead to recursion. super lets us look up the next parent in the MRO (see the first section of this answer) for child classes. If you tell super we're in the child instance's method, it will then lookup the next method in line (probably this one) resulting in recursion, probably causing a logical failure (in the answerer's example, it does) or a RuntimeError when the recursion depth is exceeded.
>>> class Polygon(object):
... def __init__(self, id):
... self.id = id
...
>>> class Rectangle(Polygon):
... def __init__(self, id, width, height):
... super(self.__class__, self).__init__(id)
... self.shape = (width, height)
...
>>> class Square(Rectangle):
... pass
...
>>> Square('a', 10, 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'
Python 3's new super() calling method with no arguments fortunately allows us to sidestep this issue.
It's been noted that in Python 3.0+ you can use
super().__init__()
to make your call, which is concise and does not require you to reference the parent OR class names explicitly, which can be handy. I just want to add that for Python 2.7 or under, some people implement a name-insensitive behaviour by writing self.__class__ instead of the class name, i.e.
super(self.__class__, self).__init__() # DON'T DO THIS!
HOWEVER, this breaks calls to super for any classes that inherit from your class, where self.__class__ could return a child class. For example:
class Polygon(object):
def __init__(self, id):
self.id = id
class Rectangle(Polygon):
def __init__(self, id, width, height):
super(self.__class__, self).__init__(id)
self.shape = (width, height)
class Square(Rectangle):
pass
Here I have a class Square, which is a sub-class of Rectangle. Say I don't want to write a separate constructor for Square because the constructor for Rectangle is good enough, but for whatever reason I want to implement a Square so I can reimplement some other method.
When I create a Square using mSquare = Square('a', 10,10), Python calls the constructor for Rectangle because I haven't given Square its own constructor. However, in the constructor for Rectangle, the call super(self.__class__,self) is going to return the superclass of mSquare, so it calls the constructor for Rectangle again. This is how the infinite loop happens, as was mentioned by #S_C. In this case, when I run super(...).__init__() I am calling the constructor for Rectangle but since I give it no arguments, I will get an error.
Super has no side effects
Base = ChildB
Base()
works as expected
Base = ChildA
Base()
gets into infinite recursion.
Just a heads up... with Python 2.7, and I believe ever since super() was introduced in version 2.2, you can only call super() if one of the parents inherit from a class that eventually inherits object (new-style classes).
Personally, as for python 2.7 code, I'm going to continue using BaseClassName.__init__(self, args) until I actually get the advantage of using super().
There isn't, really. super() looks at the next class in the MRO (method resolution order, accessed with cls.__mro__) to call the methods. Just calling the base __init__ calls the base __init__. As it happens, the MRO has exactly one item-- the base. So you're really doing the exact same thing, but in a nicer way with super() (particularly if you get into multiple inheritance later).
The main difference is that ChildA.__init__ will unconditionally call Base.__init__ whereas ChildB.__init__ will call __init__ in whatever class happens to be ChildB ancestor in self's line of ancestors
(which may differ from what you expect).
If you add a ClassC that uses multiple inheritance:
class Mixin(Base):
def __init__(self):
print "Mixin stuff"
super(Mixin, self).__init__()
class ChildC(ChildB, Mixin): # Mixin is now between ChildB and Base
pass
ChildC()
help(ChildC) # shows that the Method Resolution Order is ChildC->ChildB->Mixin->Base
then Base is no longer the parent of ChildB for ChildC instances. Now super(ChildB, self) will point to Mixin if self is a ChildC instance.
You have inserted Mixin in between ChildB and Base. And you can take advantage of it with super()
So if you are designed your classes so that they can be used in a Cooperative Multiple Inheritance scenario, you use super because you don't really know who is going to be the ancestor at runtime.
The super considered super post and pycon 2015 accompanying video explain this pretty well.
I was looking into Python's super method and multiple inheritance. I read along something like when we use super to call a base method which has implementation in all base classes, only one class' method will be called even with variety of arguments. For example,
class Base1(object):
def __init__(self, a):
print "In Base 1"
class Base2(object):
def __init__(self):
print "In Base 2"
class Child(Base1, Base2):
def __init__(self):
super(Child, self).__init__('Intended for base 1')
super(Child, self).__init__()# Intended for base 2
This produces TyepError for the first super method. super would call whichever method implementation it first recognizes and gives TypeError instead of checking for other classes down the road. However, this will be much more clear and work fine when we do the following:
class Child(Base1, Base2):
def __init__(self):
Base1.__init__(self, 'Intended for base 1')
Base2.__init__(self) # Intended for base 2
This leads to two questions:
Is __init__ method a static method or a class method?
Why use super, which implicitly choose the method on it's own rather than explicit call to the method like the latter example? It looks lot more cleaner than using super to me. So what is the advantage of using super over the second way(other than writing the base class name with the method call)
super() in the face of multiple inheritance, especially on methods that are present on object can get a bit tricky. The general rule is that if you use super, then every class in the hierarchy should use super. A good way to handle this for __init__ is to make every method take **kwargs, and always use keyword arguments everywhere. By the time the call to object.__init__ occurs, all arguments should have been popped out!
class Base1(object):
def __init__(self, a, **kwargs):
print "In Base 1", a
super(Base1, self).__init__()
class Base2(object):
def __init__(self, **kwargs):
print "In Base 2"
super(Base2, self).__init__()
class Child(Base1, Base2):
def __init__(self, **kwargs):
super(Child, self).__init__(a="Something for Base1")
See the linked article for way more explanation of how this works and how to make it work for you!
Edit: At the risk of answering two questions, "Why use super at all?"
We have super() for many of the same reasons we have classes and inheritance, as a tool for modularizing and abstracting our code. When operating on an instance of a class, you don't need to know all of the gritty details of how that class was implemented, you only need to know about its methods and attributes, and how you're meant to use that public interface for the class. In particular, you can be confident that changes in the implementation of a class can't cause you problems as a user of its instances.
The same argument holds when deriving new types from base classes. You don't want or need to worry about how those base classes were implemented. Here's a concrete example of how not using super might go wrong. suppose you've got:
class Foo(object):
def frob(self):
print "frobbign as a foo"
class Bar(object):
def frob(self):
print "frobbign as a bar"
and you make a subclass:
class FooBar(Foo, Bar):
def frob(self):
Foo.frob(self)
Bar.frob(self)
Everything's fine, but then you realize that when you get down to it,
Foo really is a kind of Bar, so you change it
class Foo(Bar):
def frob(self):
print "frobbign as a foo"
Bar.frob(self)
Which is all fine, except that in your derived class, FooBar.frob() calls Bar.frob() twice.
This is the exact problem super() solves, it protects you from calling superclass implementations more than once (when used as directed...)
As for your first question, __init__ is neither a staticmethod nor a classmethod; it is an ordinary instance method. (That is, it receives the instance as its first argument.)
As for your second question, if you want to explicitly call multiple base class implementations, then doing it explicitly as you did is indeed the only way. However, you seem to be misunderstanding how super works. When you call super, it does not "know" if you have already called it. Both of your calls to super(Child, self).__init__ call the Base1 implementation, because that is the "nearest parent" (the most immediate superclass of Child).
You would use super if you want to call just this immediate superclass implementation. You would do this if that superclass was also set up to call its superclass, and so on. The way to use super is to have each class call only the next implementation "up" in the class hierarchy, so that the sequence of super calls overall calls everything that needs to be called, in the right order. This type of setup is often called "cooperative inheritance", and you can find various articles about it online, including here and here.
What's the difference and problems involved in this curiosity:
class A(object):
def __init__(self):
super(A, self).__init__()
Than
class A(object):
def __init__(self):
pass
class B(A):
def __init__(self):
super(B, self).__init__()
Even if the first example is wrong, it works. I thought it could be a redundancy, but I heard that using super() in a class that's inherited from object is wrong, but why?
Using super(A, self).__init__() is just fine; object has an __init__ method too.
What would not work is trying to pass arguments to that method; object.__init__() takes no parameters. And for most methods other than __init__, super() in a class derived directly from object may also not work because object does not have the specific method you are trying to call.
Thus, using super(class, self).__init__() with anything other than an empty argument list requires more intimate knowledge of your class hierarchy, where any classes deriving directly from object should take care not to pass on arguments.
For any custom methods, super(class, self).other_method will most likely fail because object simply doesn't implement that method.
super(class. self) is how one interacts with what's called the MRO, or method resolution order.
A very important concept to grok. Here's Guido on MRO: http://python-history.blogspot.com/2010/06/method-resolution-order.html?m=1