Calling __init__ of all parent class with different parameters [duplicate] - python

This question already has answers here:
python multiple inheritance passing arguments to constructors using super
(4 answers)
Closed 3 years ago.
I have some class structure like this:
class A:
def __init__(self):
print("A")
class B:
def __init__(self, x):
print("B")
class C(A,B):
def __init__(self):
super(C, self).__init__() # ???
c=C()
As you can see, A and B both are parent class of C. I want to call both classes __init__ in C's __init__. I want to pass some parameter to B's __init__. Is there any way I can do this with super keyword? I think that this will work:
class C(A,B):
def __init__(self):
A.__init__()
B.__init__(5)
Should we call __init__ directly in such a way, or is there any better solution for this?

You have to provide self as parameter to parent classes' __init__().
class C(A,B):
def __init__(self):
A.__init__(self)
B.__init__(self, 5)

Related

Call derived class method in the init of a base class [duplicate]

class A:
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
B() # output: hello
In all other languages I've worked with the super constructor is invoked implicitly. How does one invoke it in Python? I would expect super(self) but this doesn't work.
In line with the other answers, there are multiple ways to call super class methods (including the constructor), however in Python 3 the process has been simplified:
Python 3
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super().__init__()
Python 2
In Python 2, you have to call the slightly more verbose version super(<containing classname>, self), which is equivalent to super()as per the docs.
class A(object):
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
super(B, self).__init__()
super() returns a parent-like object in new-style classes:
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super(B, self).__init__()
B()
With Python 2.x old-style classes it would be this:
class A:
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
A.__init__(self)
One way is to call A's constructor and pass self as an argument, like so:
class B(A):
def __init__(self):
A.__init__(self)
print "hello"
The advantage of this style is that it's very clear. It call A's initialiser. The downside is that it doesn't handle diamond-shaped inheritance very well, since you may end up calling the shared base class's initialiser twice.
Another way is to use super(), as others have shown. For single-inheritance, it does basically the same thing as letting you call the parent's initialiser.
However, super() is quite a bit more complicated under-the-hood and can sometimes be counter-intuitive in multiple inheritance situations. On the plus side, super() can be used to handle diamond-shaped inheritance. If you want to know the nitty-gritty of what super() does, the best explanation I've found for how super() works is here (though I'm not necessarily endorsing that article's opinions).
Short Answer
super(DerivedClass, self).__init__()
Long Answer
What does super() do?
It takes specified class name, finds its base classes (Python allows multiple inheritance) and looks for the method (__init__ in this case) in each of them from left to right. As soon as it finds method available, it will call it and end the search.
How do I call init of all base classes?
Above works if you have only one base class. But Python does allow multiple inheritance and you might want to make sure all base classes are initialized properly. To do that, you should have each base class call init:
class Base1:
def __init__(self):
super(Base1, self).__init__()
class Base2:
def __init__(self):
super(Base2, self).__init__()
class Derived(Base1, Base2):
def __init__(self):
super(Derived, self).__init__()
What if I forget to call init for super?
The constructor (__new__) gets invoked in a chain (like in C++ and Java). Once the instance is created, only that instance's initialiser (__init__) is called, without any implicit chain to its superclass.
Just to add an example with parameters:
class B(A):
def __init__(self, x, y, z):
A.__init__(self, x, y)
Given a derived class B that requires the variables x, y, z to be defined, and a superclass A that requires x, y to be defined, you can call the static method init of the superclass A with a reference to the current subclass instance (self) and then the list of expected arguments.
I use the following formula that extends previous answers:
class A(object):
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
super(self.__class__, self).__init__()
B()
This way you don't have to repeat the name of the class in the call to super. It can come handy if you are coding a large number of classes, and want to make your code in the initialiser methods independent of the class name.

Init functions execution in multiple inheritance in python

I am new to python and trying to understand the inheritance in python. Python has a feature of multiple inheritance. A single class can inherit more than one class at a same time. When we create an object of child class,the init function of child class is called. I want to call the init function of both the parent class of the child, but i am able to call only only one init function.I read the concept of method resolution order, by which the left most class inherited init function will be called. Please correct my code, so that the init function of both parent classes is called.
class A:
def __init__(self):
print("in A Init")
class B:
def __init__(self):
print("in B Init")
class C(B,A):
def __init__(self):
super().__init__()
print("in C Init")
cObj= C()
All the __init__ functions need to call super().__init__(), like this:
class A:
def __init__(self):
super().__init__()
print("in A Init")
class B:
def __init__(self):
super().__init__()
print("in B Init")
class C(B, A):
def __init__(self):
super().__init__()
print("in C Init")
c_obj= C()
When you invoke this you get the following output:
in A Init
in B Init
in C Init
Per the super() function documentation, it returns a reference to "a parent or sibling" of the class, whichever is next in the method resolution order. At the top of the hierarchy, it returns a reference to the implicit parent class object, which has an empty __init__ method which does nothing.
In order for this to work well, it's best for all the inherited __init__ functions to have the same signature, including the common base class; in this case, the signature is just __init__(self) (no additional arguments), and the common base class is object, which also has __init__(self) with no additional arguments, so that's all good. Another common pattern is for them all to take keyword arguments and pass through **kwargs to the next one.

How to invoke the super constructor in Python?

class A:
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
B() # output: hello
In all other languages I've worked with the super constructor is invoked implicitly. How does one invoke it in Python? I would expect super(self) but this doesn't work.
In line with the other answers, there are multiple ways to call super class methods (including the constructor), however in Python 3 the process has been simplified:
Python 3
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super().__init__()
Python 2
In Python 2, you have to call the slightly more verbose version super(<containing classname>, self), which is equivalent to super()as per the docs.
class A(object):
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
super(B, self).__init__()
super() returns a parent-like object in new-style classes:
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super(B, self).__init__()
B()
With Python 2.x old-style classes it would be this:
class A:
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
A.__init__(self)
One way is to call A's constructor and pass self as an argument, like so:
class B(A):
def __init__(self):
A.__init__(self)
print "hello"
The advantage of this style is that it's very clear. It call A's initialiser. The downside is that it doesn't handle diamond-shaped inheritance very well, since you may end up calling the shared base class's initialiser twice.
Another way is to use super(), as others have shown. For single-inheritance, it does basically the same thing as letting you call the parent's initialiser.
However, super() is quite a bit more complicated under-the-hood and can sometimes be counter-intuitive in multiple inheritance situations. On the plus side, super() can be used to handle diamond-shaped inheritance. If you want to know the nitty-gritty of what super() does, the best explanation I've found for how super() works is here (though I'm not necessarily endorsing that article's opinions).
Short Answer
super(DerivedClass, self).__init__()
Long Answer
What does super() do?
It takes specified class name, finds its base classes (Python allows multiple inheritance) and looks for the method (__init__ in this case) in each of them from left to right. As soon as it finds method available, it will call it and end the search.
How do I call init of all base classes?
Above works if you have only one base class. But Python does allow multiple inheritance and you might want to make sure all base classes are initialized properly. To do that, you should have each base class call init:
class Base1:
def __init__(self):
super(Base1, self).__init__()
class Base2:
def __init__(self):
super(Base2, self).__init__()
class Derived(Base1, Base2):
def __init__(self):
super(Derived, self).__init__()
What if I forget to call init for super?
The constructor (__new__) gets invoked in a chain (like in C++ and Java). Once the instance is created, only that instance's initialiser (__init__) is called, without any implicit chain to its superclass.
Just to add an example with parameters:
class B(A):
def __init__(self, x, y, z):
A.__init__(self, x, y)
Given a derived class B that requires the variables x, y, z to be defined, and a superclass A that requires x, y to be defined, you can call the static method init of the superclass A with a reference to the current subclass instance (self) and then the list of expected arguments.
I use the following formula that extends previous answers:
class A(object):
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
super(self.__class__, self).__init__()
B()
This way you don't have to repeat the name of the class in the call to super. It can come handy if you are coding a large number of classes, and want to make your code in the initialiser methods independent of the class name.

Polymorphism - adding to existing methods while overwriting them

I want to be able to subclass a class, and define __init__ but still run the old __init__ as well.
To illustrate, say I have the following classes:
class A(object):
def __init__(self):
self.var1 = 1
class B(A):
def __init__(self)
self.var2 = 2
doInitForA()
And I want to be able to do this:
instB = B()
print (instB.var1) #1
print (instB.var2) #2
Edited as Ignacio Vazquez-Abrams suggested. (Is it possible to edit without bumping?)
replace
doInitForA()
with
super(b, self).__init__()
You might want to look at this question: Chain-calling parent constructors in python, specifically use the super(b, self).__init__() method.
Either call a.__init__(self) or derive a from object and use super().
class a:
def __init__(self):
self.var1 = 1
class b(a):
def __init__(self)
self.var2 = 2
a.__init__(self)
You can even write super().__init__() if you are using python 3.
See this question about the use of super().
Call your father's c'tor from within your c'tor: a.__init__(self). Note that you need to pass self as first parameter. If the parent c'tor takes more parameters, pass them after self.

Chain-calling parent initialisers in python [duplicate]

This question already has answers here:
How to invoke the super constructor in Python?
(7 answers)
Closed 6 years ago.
Consider this - a base class A, class B inheriting from A, class C inheriting from B. What is a generic way to call a parent class initialiser in an initialiser? If this still sounds too vague, here's some code.
class A(object):
def __init__(self):
print "Initialiser A was called"
class B(A):
def __init__(self):
super(B,self).__init__()
print "Initialiser B was called"
class C(B):
def __init__(self):
super(C,self).__init__()
print "Initialiser C was called"
c = C()
This is how I do it now. But it still seems a bit too non-generic - you still must pass a correct type by hand.
Now, I've tried using self.__class__ as a first argument to super(), but, obviously it doesn't work - if you put it in the initialiser for C - fair enough, B's initialiser gets called. If you do the same in B, "self" still points to an instance of C so you end up calling B's initialiser again (this ends in an infinite recursion).
There is no need to think about diamond inheritance for now, I am just interested in solving this specific problem.
Python 3 includes an improved super() which allows use like this:
super().__init__(args)
The way you are doing it is indeed the recommended one (for Python 2.x).
The issue of whether the class is passed explicitly to super is a matter of style rather than functionality. Passing the class to super fits in with Python's philosophy of "explicit is better than implicit".
You can simply write :
class A(object):
def __init__(self):
print "Initialiser A was called"
class B(A):
def __init__(self):
A.__init__(self)
# A.__init__(self,<parameters>) if you want to call with parameters
print "Initialiser B was called"
class C(B):
def __init__(self):
# A.__init__(self) # if you want to call most super class...
B.__init__(self)
print "Initialiser C was called"

Categories

Resources