6

When I call the base class recursive method from the derived class, the recursive call is done against the derived method, instead of the base class method. How can I avoid that without modifying base class implementation (in example class A)?

Here is an example

class A(object):
    # recursive method
    def f(self, x):
        print x,
        if x < 0:
            self.f(x+1)
        if x > 0:
            self.f(x-1)
        if x == 0:
           print ""

class B(A):
   # Override method 
   def f(self):
       # do some pretty cool stuff
       super(B, self).f(25)

if __name__ == "__main__":
    A().f(5)
    B().f()

I've got this output:

5 4 3 2 1 0 
25
Traceback (most recent call last):
  File "./test.py", line 19, in <module>
     B().f()
  File "./test.py", line 15, in f
     super(B, self).f(25)
   File "./test.py", line 9, in f
     self.f(x-1)
  TypeError: f() takes exactly 1 argument (2 given)

Thanks in advance,

1
  • 1
    Just change the name of your function... Commented Jul 27, 2011 at 16:04

4 Answers 4

4

Name mangling is the tool for this job. This would look like this in your case:

class A(object):
    # recursive method
    def f(self, x):
        print x,
        if x < 0:
            self.__f(x+1)
        if x > 0:
            self.__f(x-1)
        if x == 0:
           print ""

    __f = f

class B(A):
   # Override method 
   def f(self):
       # do some pretty cool stuff
       super(B, self).f(25)

Explanation from the linked documentation:

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped.

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

4 Comments

Tt is generally a good idea to protect your implementations and expose your interfaces. It does lead to a lot of def f(self, x): self._f(x), but it makes it easier to avoid these problems.
ok thanks. But that's a dummy example, what can i do if i can't access to class A implementation because it its in imported module?
You could have B not subclass A, but just provide the interface that A provides. Another alternative is not to use the the same method name.
Well dynamic dispatch is one of the basics of OOP, so instead of fighting against it, I'd go back to the drawing board and think about how to design this differently.
2

In your second example, your problem is that the self you're passing along is an instance of B, not an instance of A, so when you attempt to call self.f you're calling B.f.

Unfortunately, the behavior you're seeing is really sort of how OO programming should work. Anything you do to work around this is going to be a bit of a hack around the OO paradigm. Another option which might be more explicit than using mangling, but is not necessarily "real recursion", would be to pass along the function you want to recurse on:

class A(object):
    # recursive method
    def f(self, x, func=None):

        if func is None:
            func = A.f

        print x,

        if x < 0:
            func(self,x+1,func)
        if x > 0:
            func(self,x-1,func)
        if x == 0:
           print ""

class B(A):
   # Override method 
   def f(self):
       # do some pretty cool stuff
       super(B, self).f(25)

if __name__ == "__main__":
    A().f(5)
    B().f()

This probably isn't the best way this could be written, but I think it gets the idea across. You could alternately try passing A.f in from your call in B.f.

Comments

1

I would suggest renaming the base classes f method to a private method called _f and having that recurse. You can then introduce a new f method to the base class which just calls _f. Then your free to change f in the subclass.

However it may not be considered good practice to change the method signature in a subclass.

class A(object):
    def f(self, x):
        return self._f(x)

    # recursive method
    def _f(self, x):
        print x,
        if x < 0:
            self._f(x+1)
        if x > 0:
            self._f(x-1)
        if x == 0:
           print ""

class B(A):
   # Override method 
   def f(self):
       # do some pretty cool stuff
       super(B, self).f(25)

if __name__ == "__main__":
    A().f(5)
    B().f()

Comments

1

If you can't modify A's implementation, you can take advantage of the difference in function signatures.

class B(A):
    def f(self, x=None):
        if x is None:
            # do some pretty cool stuff
            self.f(25)
        else:
            super(B, self).f(x)

2 Comments

"if x=None:" should be "if x == None:" or better still "if x is None:".
@awatts: fixed but this comment is too short.

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.