Does a subclass need to initialize an empty super class? - python

This just came into my mind.
class Parent:
pass
class Child(Parent):
def __init__(self):
# is this necessary?
super().__init__()
When a class inherits an empty class, do the subclass need to initialize it and why?

This is just fine:
class Parent:
# the __init__ is inherited from parent
pass
class Child(Parent):
# the __init__ is inherited from parent
pass
This is also fine:
class Parent:
# the __init__ is inherited from parent
pass
class Child(Parent):
def __init__(self):
# __init__ is called on parent
super().__init__()
This may seem ok, and will usually work fine, but not always:
class Parent:
# the __init__ is inherited from parent
pass
class Child(Parent):
def __init__(self):
# this does not call parent's __init__,
pass
Here is one example where it goes wrong:
class Parent2:
def __init__(self):
super().__init__()
print('Parent2 initialized')
class Child2(Child, Parent2):
pass
# you'd expect this to call Parent2.__init__, but it won't:
Child2()
This is because the MRO of Child2 is: Child2 -> Child -> Parent -> Parent2 -> object.
Child2.__init__ is inherited from Child and that one does not call Parent2.__init__, because of the missing call to super().__init__.

No it isn't necessary. It is necessary when you want the parent's logic to run as well.
class Parent:
def __init__(self):
self.some_field = 'value'
class Child(Parent):
def __init__(self):
self.other_field = 'other_value'
super().__init__()
child = Child()
child.some_field # 'value'

There is no requirement in the language that subclass need to call __init__ of superclass. Despite this, it is almost always needed because superclass initializes some base attributes and the subclass expects them to be initialized. So, if the superclass __init__ is empty, you don't need to call it, otherwise you need to.

Related

Inheritance: How to make parent method work with other parent methods?

So I have two classes, where one inherits from another and overrides all parent methods:
class Parent:
def name(self):
return 'parent'
def run(self):
print(f'calling method from parent: I am {self.name()}')
class Child(Parent):
def name(self):
return 'child'
def run(self):
print(f'calling method from child: I am {self.name()}')
return super().run()
Running the following piece Child().run() triggers method run both for child and parent, and the output is:
calling method from child: I am child
calling method from parent: I am child
And result is clear - since we have redefined method name, new version is used in both run methods. (I am child on both lines)
And that's the main problem - the way I want it to work is for parent run method to use parent name.
What I have accomplished so far is replacing super with self.__class__.__mro__[1], so that method looks like
def run(self):
print(f'calling method from child: I am {self.name()}')
return self.__class__.__mro__[1]().run()
The way it works is it gets parent class using method resolution order and creates instance of parent class. It works fine and now result is:
calling method from child: I am child
calling method from parent: I am parent
But I don't like this solution:
Single inheritance - since we hardcode parent class index, we cannot make it work with several parent classes
Using MRO doesn't feel right for this case
Here we assume __init__ doesn't take extra arguments
I think clue is in changing self.name in parent method so that it will use parent method explicitly, but I don't know how to achieve this.
You can find the current class that the method is defined in by using __class__:
class Parent:
def name(self):
return 'parent'
def run(self):
print(f'calling method from parent: I am {__class__.name(self)}')
I'd suggest making name a name-mangled (__) attribute that's private to the class:
class Parent:
__name = 'parent'
def run(self):
print(f'calling method from parent: I am {self.__name}')
class Child(Parent):
__name = 'child'
def run(self):
print(f'calling method from child: I am {self.__name}')
return super().run()
Child().run()
# calling method from child: I am child
# calling method from parent: I am parent

Prevent a method that is called in the parent constructor from being called in the child constructor

Suppose I have a parent class and a child class that inherits from the parent.
class Parent:
def __init__(self)
stubborn()
class Child():
def __init__(self):
super().__init__(self)
I do not want the stubborn method to be called anytime I call the parent constructor
in the child class. How do I approach this?
You can define a classmethod of Parent that checks whether or not you are in Parent, then use that to determine whether to call stubborn
class Parent:
def __init__(self):
if self.is_parent():
self.stubborn()
#classmethod
def is_parent(cls):
return cls is Parent
def stubborn(self):
print("stubborn called")
class Child(Parent): pass
p = Parent() # stubborn called
c = Child() # no output
You wouldn't be able to do anything about it in parent.__init__() without actually changing that function or stubborn().
But, as the child, you could stop the stubborn() method from doing anything important by temporarily making it a stub:
class Child():
def __init__(self):
old_stubborn = self.stubborn
self.stubborn = lambda:None # stub function that does nothing
super().__init__(self)
# put stubborn() back to normal
self.stubborn = old_stubborn

Python overriden methods called from superclass

There are lot of information about mangling and it's usage, however I am struggling to understand the following piece of code:
class Parent:
NAME = 'PARENT'
def __init__(self):
self.print_me()
def print_me(self):
print(f"Parent class {self.NAME}")
class Child(Parent):
NAME = 'CHILD'
def __init__(self):
super().__init__()
def print_me(self):
print(f"Child class {self.NAME}")
c = Child()
Can someone please explain how the overriden method (print_me) is called from the parent class init and does not print Parent class PARENT?
If I use mangling both for NAME and print_me the method is not overriden and thus it's called from the parent which is expected.
Here the object(c) is child class object
In child class the constructor calls the parent class and the parent class constructor calls the print_me method
Here you called the child object so it will execute the child method. If the print_me method is not available in child then it will execute parent method
If you needed it to print the parent function, you should instead create the parent object.
c = Parent()

Inheritance in Python for variable that's not parameter

In Python, I'm using inheritance for a class. The initial init for the main parent class is below:
def __init__(self, Date = None):
self.Date = Date
self.DatabaseClass = Database()
self.Connection = self.DatabaseClass.databaseConnection()
I've inherited the class into the child class, but am wondering what the correct approach would be to inherit DatabaseClass and Connection variables, i.e., what would be in def __init__?
You just need to call the inherited __init__ method from your own class's __init__ method.
class Child(Parent):
def __init__(self, Date=None, other, arguments):
super().__init__(Date)
# ...

Refer to a class outside its method?

I need to deliver something like this in my program
class the_class_name(Parent):
the_attribute = self.parent_class_method()
#the parent class method will return a value
#but I cannot use self here since there's no self
How can I carry this out? Is there any other alternative that can do the job for me?
I have tried using __init__ like this:
def __init__(self):
Parent.__init__(self)
self.attribute = self.the_method()
But then I have problem creating the object, it won't receive any parameters that the Parent class normally receives anymore
Sounds like you are looking for __init__:
class TheClassName(Parent):
def __init__(self):
# Set attribute to the result of the parent method
self.attribute = super(TheClassName, self).the_method()
EDIT
If your parent class has parameters in it's own __init__ function, include them in the child class:
class Parent(object):
def __init__(self, foo, bar):
...
#classmethod
def the_method(cls):
...
class TheClassName(Parent):
def __init__(self, foo, bar):
super(TheClassName, self).__init__(foo, bar)
self.attribute = super(TheClassName, self).the_method()
I don't quite understand why you don't just call the parent method on your child object when you need the value though.
There is no self at that point of the creation of the subclass, nor is there an instance of the Parent class. That means the only Parent class methods you could call would have to be either static or class methods.
To demonstrate:
class Parent(object):
#staticmethod
def static_method():
return 42
#classmethod
def class_method(cls):
return 43
class TheClassName(Parent):
the_attribute = Parent.static_method()
another_attribute = Parent.class_method()
print(TheClassName.the_attribute) # -> 42
print(TheClassName.another_attribute) # -> 43
You must use class methods, declared with the #classmethod decorator, or a #staticmethod. The #classmethod decorator is preferable so that inheritance is handled correctly, i.e. the method is invoked on the derived class (a bit of a technicality, if you are still learning this).
class Alpha(object):
#classmethod
def method1(cls):
return 'method1 has been called on {}'.format(cls)
class Beta(Alpha):
def __init__(self):
self.myattr = Beta.method1()
print(Beta().myattr)
method1 has been called on class <'__main__.Beta'>
Use
super(ClassName, self).methodname(arg)
inside a method
def child_method(self, arg):
super(ClassName, self).methodname(arg)
You cannot use self outside a method.

Categories