简体   繁体   中英

override recursive method in python

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,

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.

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 Bf .

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 Af in from your call in Bf .

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)

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM