当我从派生类调用基类递归方法时,递归调用是针对派生方法而不是基类方法完成的。如何避免而不修改基类实现(在示例类A中)?
这是一个例子
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()
我有这个输出:
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)
提前致谢,
答案 0 :(得分:4)
Name mangling是这项工作的工具。在你的情况下,这看起来像这样:
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)
链接文档的说明:
__spam
形式的任何标识符(至少两个主要下划线, 最多一个尾随下划线)在文本上被替换为_classname__spam
,其中classname是当前的类名 剥离前导下划线。
答案 1 :(得分:1)
在您的第二个示例中,您的问题是您传递的self
是B
的实例,而不是A
的实例,因此当您尝试调用{ {1}}您正在呼叫self.f
。
不幸的是,您所看到的行为实际上是OO编程应该的工作方式。你为解决这个问题所做的任何事情都会对OO范式产生一些影响。另一个可能比使用修改更明确的选项,但不一定是“真正的递归”,将传递你想要递归的函数:
B.f
这可能不是写这篇文章的最佳方式,但我认为它可以解决这个问题。您也可以尝试通过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()
中的A.f
传递B.f
。{/ p>
答案 2 :(得分:1)
如果你无法修改A
的实现,你可以利用功能签名的不同。
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)
答案 3 :(得分:0)
我建议将基类f
方法重命名为名为_f
的私有方法并进行递归。然后,您可以向只调用f
的基类引入新的_f
方法。然后您可以自由更改子类中的f
。
但是,在子类中更改方法签名可能不是一种好的做法。
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()