Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling base class method after child class __init__ from base class __init__?

This is a feature I miss in several languages and wonder if anyone has any idea how it can be done in Python.

The idea is that I have a base class:

class Base(object):
    def __init__(self):
        self.my_data = 0
    def my_rebind_function(self):
        pass

and a derived class:

class Child(Base):
    def __init__(self):
        super().__init__(self)
        # Do some stuff here
        self.my_rebind_function() # <==== This is the line I want to get rid of
    def my_rebind_function(self):
        # Do stuff with self.my_data

As can be seen above, I have a rebound function which I want called after the Child.__init__ has done its job. And I want this done for all inherited classes, so it would be great if it was performed by the base class, so I do not have to retype that line in every child class.

It would be nice if the language had a function like __finally__, operating similar to how it operates with exceptions. That is, it should run after all __init__-functions (of all derived classes) have been run, that would be great. So the call order would be something like:

Base1.__init__()
...
BaseN.__init__()
LeafChild.__init__()
LeafChild.__finally__()
BaseN.__finally__()
...
Base1.__finally__()

And then object construction is finished. This is also kind of similar to unit testing with setup, run and teardown functions.

like image 831
Robert Avatar asked Jul 09 '17 20:07

Robert


People also ask

Can a child class call base class methods?

A child class can access the data members of its specific base class, i.e., variables and methods. Within this guide, we will be discussing different ways to execute or call the base call function in C++.

Can you call methods in __ init __?

Calling other methods from the __init__ methodWe can call other methods of the class from the __init__ method by using the self keyword. The above code will print the following output.

How do we invoke the Init method of a parent class from within a child class?

Use super(). __init()__ to call the immediate parent class constructor in Python. Calling a parent constructor within a child class executes the operations of the parent class constructor in the child class.

Why does a class need to manually call a superclass's __ init __ method?

The main reason for always calling base class _init__ is that base class may typically create member variable and initialize them to defaults. So if you don't call base class init, none of that code would be executed and you would end up with base class that has no member variables.


2 Answers

You can do this with a metaclass like that:

    class Meta(type):
        def __call__(cls, *args, **kwargs):
            print("start Meta.__call__")
            instance = super().__call__(*args, **kwargs)
            instance.my_rebind_function()
            print("end Meta.__call__\n")
            return instance


    class Base(metaclass=Meta):
        def __init__(self):
            print("Base.__init__()")
            self.my_data = 0

        def my_rebind_function(self):
            pass


    class Child(Base):
        def __init__(self):
            super().__init__()
            print("Child.__init__()")

        def my_rebind_function(self):
            print("Child.my_rebind_function")
            # Do stuff with self.my_data
            self.my_data = 999


    if __name__ == '__main__':
        c = Child()
        print(c.my_data)

By overwriting Metaclass.__call__ you can hook after all __init__ ( and __new__) methods of the class-tree have run an before the instance is returned. This is the place to call your rebind function. To understand the call order i added some print statements. The output will look like this:

start Meta.__call__
Base.__init__()
Child.__init__()
Child.my_rebind_function
end Meta.__call__

999

If you want to read on and get deeper into details I can recommend following great article: https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

like image 111
Robert_Jordan Avatar answered Sep 27 '22 21:09

Robert_Jordan


I may still not fully understand, but this seems to do what I (think) you want:

class Base(object):
    def __init__(self):
        print("Base.__init__() called")
        self.my_data = 0
        self.other_stuff()
        self.my_rebind_function()

    def other_stuff(self):
        """ empty """

    def my_rebind_function(self):
        """ empty """

class Child(Base):
    def __init__(self):
        super(Child, self).__init__()

    def other_stuff(self):
        print("In Child.other_stuff() doing other stuff I want done in Child class")

    def my_rebind_function(self):
        print("In Child.my_rebind_function() doing stuff with self.my_data")

child = Child()

Output:

Base.__init__() called
In Child.other_stuff() doing other stuff I want done in Child class
In Child.my_rebind_function() doing stuff with self.my_data
like image 25
martineau Avatar answered Sep 27 '22 23:09

martineau