Let suppose we have defined two classes:
class A():
def __init__(self):
self.a = 0
class B():
def __init__(self):
self.b = 0
Now, we want to define a third class C that inherits from A and B:
class C(A, B):
def __init__(self):
A.__init__(self) # how to do this using super()
B.__init__(self) # how to do this using super()
You did not specify whether you are Python 2 or Python 3 and it matters as we shall see. But either way, if you will be using super() in a derived class to initialize the base classes, then the base classes must use super() also. So,
For Python 3:
class A():
def __init__(self):
super().__init__()
self.a = 0
class B():
def __init__(self):
super().__init__()
self.b = 0
class C(A, B):
def __init__(self):
super().__init__()
For Python 2 (where classes must be new-style classes) or Python 3
class A(object):
def __init__(self):
super(A, self).__init__()
self.a = 0
class B(object):
def __init__(self):
super(B, self).__init__()
self.b = 0
class C(A, B):
def __init__(self):
super(C, self).__init__()
Related
class One:
def __init__(self):
self.one = 1
class Two:
def __init__(self):
self.two = 2
class Three(One, Two):
def __init__(self):
self.three = 3
super().__init__()
obj = Three()
print(obj.one)
print(obj.two)
print(obj.three)
i am currently self learning OOP, i am having a hard time understanding why the object was able to print the attribute from Class One but not also the one from Class Two despite me using the super function, the error raised is AttributeError: 'Three' object has no attribute 'two'. How do we inherit from multiple classes?
super().__init__() in Three will only refer to the first class in Method Resolution Order. In order to call all the __init__, you'd need to do super() in all of them:
class One:
def __init__(self):
self.one = 1
super().__init__()
class Two:
def __init__(self):
self.two = 2
super().__init__()
Or, if you don't want to / can't modify parent class signatures, you refer to the classes directly instead of using super, so they will all be called regardless of MRO:
class Three(One, Two):
def __init__(self):
self.three = 3
One.__init__()
Two.__init__()
class One:
def __init__(self):
self.one = 1
super().__init__()
class Two:
def __init__(self):
self.two = 2
super().__init__()
class Three(One,Two):
def __init__(self):
self.three = 3
super().__init__()
obj = Three()
print(obj.one)
print(obj.two)
print(obj.three)
use super().__init__method in every class.
if you dont want to use it. you can call init methods of class one and class two in init method of class three.
Please find the code below
class Base:
def __init__(self, **kwargs):
self.b1 = kwargs['a']
self.b2 = kwargs['b']
class Child1(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child1).__init__(**kwargs)
print(self.b1)
print(self.b2)
def call(self):
self.b1 -= 10
self.b2 -= 20
class Child2(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child2).__init__(**kwargs)
print(self.b1)
print(self.b2)
When I call using the below:
obj1 = Child1(a=20,b=30,c=5)
obj1.call() #output 20, 30
obj2 = Child2(c=5)
I want the output of b1 and b2 to be reflected since obj1 has already changed the value
Please advice
you can do it like this
class Base:
instances = []
def __init__(self, **kwargs):
self.b1 = kwargs['a']
self.b2 = kwargs['b']
Base.instances.append(self)
class Child1(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child1,self).__init__(**kwargs)
print(self.b1)
print(self.b2)
def call(self):
self.b1 -= 10
self.b2 -= 20
class Child2(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child2,self).__init__(a = Base.instances[0].b1, b = Base.instances[0].b2)
print(self.b1)
print(self.b2)
obj1 = Child1(a=20,b=30,c=5)
obj1.call()
obj2 = Child2(c=5)
All new instances initiated with Base are saved inside Base.instances. Then you can take the first one and use its b1 and b2 attributes when you create something from Child2 class.
Suppose I have the following class inheriting from classes A and B:
class A:
def __init__(self):
self.x = 2
class B:
def __init__(self,u):
self.y = u + 2
class C(A,B):
def __init__(self):
#self.y should be 4 here
How do I initialize B only after initializing A? Using super(C,self).__init__() doesn't let me use attributes of A into B.
You don't HAVE to use super.
class A:
def __init__(self):
self.x = 2
class B:
def __init__(self,u):
self.y = u + 2
class C(A,B):
def __init__(self):
A.__init__(self)
B.__init__(self, self.x)
Now, that does mean some pretty tight coupling, in that C has to be way too aware of what A.__init__ does.
Just do this:
class A:
def __init__(self):
print("A was initialized")
self.x = 2
def getX(self):
return self.x
class B:
def __init__(self, u):
print("B was initialized")
self.u = u +2
class C(A,B):
def __init__(self, **kw):
A.__init__(self)
B.__init__(self, self.getX())
Alternatively, with super:
class A:
def __init__(self):
self.x = 2
class B:
def __init__(self,u):
self.y = u + 2
class C(A,B):
def __init__(self):
super().__init__()
super(A, self).__init__(self.x)
If you want to pass attributes in between classes use something like a return statement. Then in your B class use whatever the A class returned.
I use Python 3.6.3
I have following code:
class Parent:
def __init__(self, **kw):
print("init parent")
class PP:
def __init__(self, **kw):
print("init PP")
class Child(PP, Parent):
def __init__(self, **kw):
print("init child")
super().__init__()
exp=Child()
I expect:
init child
init PP
init parent
but I got:
init child
init PP
when I try to print the MRO,I got the correct answer.
print(exp.__class__.mro())
[<class '__main__.Child'>, <class '__main__.PP'>, <class '__main__.Parent'>, <class 'object'>]
Why is there no print of parent?
Python doesn't automatically call __init__ of Parent. You have to do it explicitly with super().__init__() in PP:
class Parent:
def __init__(self, **kw):
print("init parent")
class PP:
def __init__(self, **kw):
print("init PP")
super().__init__()
class Child(PP, Parent):
def __init__(self, **kw):
print("init child")
super().__init__()
exp = Child()
Now the output is:
init child
init PP
init parent
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, color):
self.color = color
fido = Dog(legs = 4, color = "brown")
This would spute out an error message. How would I do something like that where I add parameters to the subclass that doesn't pertain to the superclass.
Try this:
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, legs, color):
super().__init__(legs)
self.color = color
fido = Dog(legs=4, color="brown")
That's not how inheritance works. When you inherit from another class, the super-class's parameters are not automatically added to the sub-class's parameter list. You must explicitly accept the desired parameters in your sub-class's constructor and pass them on to the super class's constructor:
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, color, legs):
super().__init__(legs)
self.color = color
fido = Dog(legs = 4, color = "brown")
Here's an example from a tutorial which explains inheritance and shows how to do this. You need to call the parent class's init function as in this similar example from this tutorial:
class Pet(object):
def __init__(self, name, species):
self.name = name
self.species = species
def getName(self):
return self.name
def getSpecies(self):
return self.species
def __str__(self):
return "%s is a %s" % (self.name, self.species)
class Dog(Pet):
def __init__(self, name, chases_cats):
Pet.__init__(self, name, "Dog")
self.chases_cats = chases_cats
def chasesCats(self):
return self.chases_cats
You still have to pass in the legs argument for Dog, and then use super:
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, color, legs):
super().__init__(legs)
self.color = color
fido = Dog(legs = 4, color = "brown")