I have a very naïve question. I have the following code in Python:
class A:
def __init__(self):
print("constructor A")
class B(A):
pass
ob = B()
It gives the following output:
constructor A
Similarly in the following code:
class A:
def __init__(self,name):
self.name = name
print(f'{self.name}')
class B(A):
def __init__(self):
print('Class B constructor')
ob1 = B()
ob2 = B('abc')
Shouldn't the output be:
class B constructor
abc
In fact it gives the following error:
TypeError: B.__init__() takes 1 positional argument but 2 were given
Isn't def __init__(self,name)
of class A
gets inherited in class B
and can't we call it using ob2 = B('abc')
?
CodePudding user response:
If you want the __init__()
in A
to be called, you have to do it yourself:
class A:
def __init__(self, name):
self.name = name
print(f'{self.name}')
class B(A):
def __init__(self, name):
print('Class B constructor')
super().__init__(name):
ob2 = B('abc')
Output
class B constructor
abc
CodePudding user response:
You are trying to override constructor inside class B. class B inheritances from class A. And class A constructor except name argument. You don't need add init method inside B class here. One of the advantage using OOP is to reduces repetition. You decided to which parameters parent class will have. If you don't use parent class attributes in child class then there is no logic to create parent class. In short, parent class store attributes and methods in common, and if you want, you can add more attributes and method to child classes.
Code snippet will be like this
class A:
def __init__(self,name):
self.name = name
print(f'{self.name}')
class B(A):
def __init__(self,name):
super().__init__(name, ...) # here you can add attributes that is specific to B class
print('Class B constructor')
ob2 = B('abc')
CodePudding user response:
class A:
def __init__(self, name):
self.name = name
print(f'{self.name}')
class B(A):
def __init__(self, *args):
if len(args) == 1:
super(B, self).__init__(name=args[0])
else:
print('Class B constructor')
ob1 = B()
ob2 = B('abc')
*args
can control how many objects you enter, in that situation we can enter 1 or 0 objects.
if you enter 0 objects in your constructor, it will generate ('Class B constructor')
, but if you enter 1 object, with super()
method you call the A class constructor and name
is equals to object, that is entered in the constructor.
CodePudding user response:
Just to mention, __init__
is not constructor, it's initializer. It initializes the newly created object returned from __new__
.
No, it Python attributes(including methods) of the classes are resolved using mro
(Method Resolution Order), Whenever Python finds that, it stops going further.
In this example, Python didn't find fn
in C, so it checks B, then A, and now it finds it. (If it didn't find it in A, it checks object
class which is the last class in every class's MRO. In that case it raises AttributeError
because object
doesn't have fn
either)
class A:
@staticmethod
def fn():
print("fn in A")
class B(A):
pass
class C(B):
pass
print(C.mro())
C.fn()
output:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
fn in A
If for example B
has defined fn
, it stops there:
class A:
@staticmethod
def fn():
print("fn in A")
class B(A):
@staticmethod
def fn():
print("fn in B")
class C(B):
pass
print(C.mro())
C.fn()
output:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
fn in B
Same thing happens to __init__
.
If you want your code to work, you need to call the A
's initializer inside the B
's initializer. Note that the signature of the B
's __init__
should compatible with the A
's __init__
. By compatible I mean it should take at least the number of parameters that A
's __init__
takes, because you're going to pass those parameters to A.__init__
:
class A:
def __init__(self, name):
print("Class A initializer")
self.name = name
print(f"{self.name}")
class B(A):
def __init__(self, name):
super().__init__(name)
print("Class B initializer")
ob2 = B("abc")
CodePudding user response:
it's because you __init__
take only one argument self
which is always passed you need to add name to the definition of B
class A:
def __init__(self,name):
self.name = name
print(f'{self.name}')
class B(A):
def __init__(self, name):
print('Class B constructor')
ob2 = B('abc')