Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Inheritance: Calling Methods Inside Methods

I'm new to Python and trying to understand the best "Pythonic" practices for OO and inheritance.

Here's a simplified version of something I'm trying to do: Let's say I have a base class A that has an initialization method, which, in turn, calls another method that sets some internal parameters -- I'd like to have the latter method accessible to clients as an independent function/service that can be reused after initialization:

class A(object):

    def __init__(self):

        print "Entered A's __init__"

        #Initialization specific to A:
        print "Calling A's set_params"
        self.set_params()

    def set_params(self):

        print "Entered A's set_params"      

        #Parameter setting specific to A:
        #...

Then as expected, the output of A() prints the following:

Entered A's __init__
Calling A's set_params
Entered A's set_params

So far there's no problem. Next, I add a sub class B that inherits from A but has more specific tasks going on in addition to the inherited ones:

class B(A):

    def __init__(self):

        print "Entered B's __init__"

        #Inheriting initialization from A:
        print "Calling A's __init__"
        super(B, self).__init__()

        #More initialization specific to B:
        #...

    def set_params(self):

        print "Entered B's set_params"

        #Inheriting parameter setting from A:
        print "Calling A's set_params"
        super(B, self).set_params()

        #More parameter setting specific to B:
        #...

The problem is that I expect the initializer A.__init__ called by B.__init__ to operate completely independently of how I'm overriding the functions of B, so that overriding the functions of B does not change the behavior of A when instantiating B. In this case, I need A.__init__ to call A.set_params as before rather than calling B.set_params, and disregard the fact that the latter is being overridden.

In other words, in this case I obtain the following output after running B():

Entered B's __init__
Calling A's __init__
Entered A's __init__
Calling A's set_params
Entered B's set_params
Calling A's set_params
Entered A's set_params

And the question is, what should I do to get this instead after running B()?

Entered B's __init__
Calling A's __init__
Entered A's __init__
Calling A's set_params
Entered A's set_params

The problem would disappear if I simply got rid of A.set_params and put its code content inside A.__init__, but as I mentioned, I'd like it to be separate and accessible by client code independently.

I understand that it has something to do with the fact that functions are bound to instances in this case rather than to classes, and I have tried static methods, class methods, and abstract methods as well, but I could not figure out the correct combination to solve this problem.

Some insight would be greatly appreciated! :-)

like image 534
Morad B. Avatar asked Sep 02 '26 14:09

Morad B.


1 Answers

Yeah, designing for inheritance is tricky like that. People don't put as much thought as they really should into what overridden methods do or don't affect, and they don't do enough to document how overriding methods affects other methods.

If you want to bypass overrides for that set_params call, you can explicitly specify which class's method you want to call:

class A(object):
    def __init__(self):
        ...
        A.set_params(self)

or you can add a __set_params method that won't get overridden and call that from __init__ and set_params:

class A(object):
    def __init__(self):
        ...
        self.__set_params()
    def set_params(self):
        self.__set_params()
    def __set_params(self):
        # actual implementation here

One way, you have to type out the class name explicitly every time, and the other way, you have to write up another method definition. Which one works better depends on how long your class name is and how many times you need to use the method.

like image 89
user2357112 supports Monica Avatar answered Sep 04 '26 04:09

user2357112 supports Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!