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 <开发者_Go百科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 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
.
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()
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)
精彩评论