1

I have given a class A with methods f and g. In the implementation of A.f, the method self.g is called, i.e. A.g is used. (I am not able/willing to change this class A since it comes from a python package.)

Now I want to build a child class B of A and want to overwrite the methods f and g. In the implementation of B.f, I call super().f, i.e. A.f is used. In the implementation of B.g., I call self.f, i.e. B.f is used.

I would expect that everything is well defined: B.g calls B.f calls A.f calls A.g

In fact, I get a RecursionError as I am running into an infinite number of recursions: B.g calls B.f calls A.f calls B.g

What do I not understand correctly?

Here is a implementation:

class A:
    def f(self):
        print('Method A.f was called.')
        self.g()

    def g(self):
        print('Method A.g was called.')

class B(A):
    def f(self):
        print('Method B.f was called.')
        super().f()

    def g(self):
        print('Method B.g was called.')
        self.f()

b = B()
b.g()

For clarification: In my application, A is a scikit-learn class, f is fit and g is fit_transform. In this scikit-learn class, fit_transform is explicitly overwritten, and fit unfortunately uses fit_transform. To ensure that my child class B does not inherit fit_transform from A, I have to redefine it in the usual way, and this leads to infinite recursion as explained.

1
  • self.g() is actually b.g() as in your initial call. Commented May 16, 2020 at 15:41

3 Answers 3

1

The g method of B overwrites the one of A as you said, meaning A.f will call B.g, if you change the name of the method B.g your code will run as you expect it to

Sign up to request clarification or add additional context in comments.

3 Comments

Is there a solution without changing the name of B.g? A is a scikit-learn transformer, f is fit and g is fit_transform. As this is standard terminology throughout scikit-learn and beyond, I want to avoid changing it for my subclass.
I think the solution given by rdas would work well in your case then
In this case, my subclass B does not inherit all the other attributes from A, I would have to access them in a more complicated way. I am (almost) sure that there is a more elegant solution to this. The critical point seems to super(), but I cannot find a solution.
1

What do I not understand correctly?

Even though self.g() was called within A.f, the value that was passed as self is still an instance of B, so B.g is looked up by this operation rather than A.g.

It would help if you could explain what problem you are trying to solve with this structure. In particular, I don't understand why, for any real-world code, it would be useful within the B class for g to call upon f, but in the base class to do it the other way around.

Comments

0

self is bound to the B object on which .g() was called.

Try replacing the inheritance with composition instead:

class A:
    def f(self):
        print('Method A.f was called.')
        self.g()

    def g(self):
        print('Method A.g was called.')

class B:
    def __init__(self, a):
        self.a = a

    def f(self):
        print('Method B.f was called.')
        self.a.f()

    def g(self):
        print('Method B.g was called.')
        self.f()

a = A()
b = B(a)
b.g()

Output:

Method B.g was called.
Method B.f was called.
Method A.f was called.
Method A.g was called.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.