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')?
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")
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
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')
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.
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')
I have one base class constructor. from that i want to inherit into class method. But it showing the error like TypeError: __init__() missing 1 required positional argument: 'name'
Here is my code snippet.
class A:
def __init__(self,name):
self.name = name
def m1(self):
print(self.name)
class B(A):
#classmethod
def m2(cls):
super(B,cls).__init__(cls.m1)
b=B('siddarth')
b.m2 ()
Here it is another example. but without having any parameters in constructor it is working fine.
class A:
def __init__(self):
print('This is constructor method..!!')
class B(A):
#classmethod
def m2(cls):
super(B,cls).__init__(cls)
b=B('siddarth')
b.m2()
You can code it like this:
class A:
def __init__(self,name):
self.name = name
def m1(self):
print(self.name)
class B(A):
def __init__(self, cls):
super(B, self).__init__(cls)
b=B('siddarth')
b.m1()
OUTPUT
siddarth
So basically my problem seems like this.
class A():
def func(self):
return 3
class B():
def func(self):
return 4
class AA(A):
def func(self):
return super(AA, self).func
class BB(B):
def func(self):
return super(BB, self).func
The func function is doing some work and one of the things it does is getting some attribute(or running method or whatever) from it's parent class.
Since func originally does the same logic at both cases (except that only parent class changes) I'd like to do this with decorators.
Is it possible? if so how to do it? Do I have somehow to pass parent-class as a argument?
I'll be very grateful for answers it's been bothering me for a while now.
There is no need to use super to access data attributes of a parent class.
Neither does a class need a parent in order for access to data attributes to work.
You can use a mixin to do the job:
# A and B stay the same - they still have a c attribute
class A():
c = 3
class B():
c = 4 # I've changed B to make it clear below
#Instead have a mixin which defines func()
class Mixin:
def func(self):
# func has its behaviour here
return self.c
class AA(Mixin, A):
pass
class BB(Mixin, B):
pass
a = AA()
b = BB()
print(a.func())
print(b.func())
Output:
3
4
You could do it with a single class decorator by defining a generic method inside of it that does what you want, and then adding it to the class being decorated. Here's what I mean:
def my_decorator(cls):
def call_super_func(self):
return super(type(self), self).func()
setattr(cls, 'call_super_func', call_super_func)
return cls
class A():
def func(self):
print('in A.func')
return 3
class B():
def func(self):
print('in B.func')
return 4
#my_decorator
class AA(A):
def func(self):
print('in AA.func')
return self.call_super_func()
#my_decorator
class BB(B):
def func(self):
print('in BB.func')
return self.call_super_func()
aa = AA()
aa.func()
bb = BB()
bb.func()
Output:
in AA.func
in A.func
in BB.func
in B.func
Of course you could eliminate the need to do this by just defining baseclass for A and B that has a call_super_func() method in it that they would then both inherit.
Example
class Parent:
def foo(self):
print('parent')
class DerivedA(Parent):
def foo(self):
print('derived A')
class DerivedB(Parent):
def foo(self):
print('derived B')
def bar(passed_in_func):
temp = [DerivedA(), DerivedB()]
for derived in temp:
passed_in_func(derived)
bar(Parent.foo)
Output:
parent
parent
Output Desired:
derived A
derived B
Is there any way to call the derived class' function bar with the following constraints?
There are multiple derived classes from Parent
bar() will not necessarily know which of the derived classes is passed in
The caller of bar() will not know which derived class function signature to pass in
EDIT
I know of one way to do this, but I see it as a little hacky:
def bar(passed_in_func):
temp = [DerivedA(), DerivedB()]
for derived in temp:
getattr(derived, passed_in_func)()
bar('foo')
Here's a generic way of doing it that would work for immediate subclasses:
class Parent:
def foo(self):
print('parent')
class DerivedA(Parent):
def foo(self):
print('derived A')
class DerivedB(Parent):
def foo(self):
print('derived B')
def bar(passed_in_func):
classname = passed_in_func.__qualname__.split('.')[0]
parent = eval(classname)
for derived in parent.__subclasses__():
getattr(derived(), passed_in_func.__name__)()
bar(Parent.foo)
Output:
derived A
derived B
i am new to OOP.
i have a parent class with a method that i wanna access in my subclass. But i cannot figure out the right syntax for that. I cannot find a clear cut example anywhere
Members in the base class are simply available to the subclass as well (unless they are overwritten):
class Base:
def example (self):
print('This is in the base class')
class Subclass (Base):
def test (self):
self.example()
An object of type Subclass can now access example directly or indirectly:
>>> x = Subclass()
>>> x.test()
This is in the base class
>>> x.example()
This is in the base class
class Parent(object):
def __init__(self, name):
self.name = name
def output(self):
print self.name
class Child(Parent):
def __init__(self, name, age):
Parent.__init__(self, name)
self.age = age
def output(self):
super(Child, self).output()
print self.age
if __name__ == '__main__':
a = Parent("wy")
b = Child("zhang", 10)
a.output()
b.output()
You can try this code.