2011-07-27 67 views
5

当我从派生类中调用基类递归方法时,递归调用是针对派生方法而不是基类方法完成的。如何在不修改基类实现(例如类A)的情况下避免该覆盖python中的递归方法

下面是一个例子

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) 

由于提前,

+1

只是改变你的功能的名称... – JBernardo

回答

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是当前类名称,其中 前导下划线被剥离。

+0

Tt通常是一个好主意,以保护你的实现和暴露你的接口。它确实导致了很多'def f(self,x):self._f(x)',但它更容易避免这些问题。 – cwallenpoole

+3

如果可能,通常最好避免名称变形。 – awatts

+0

好的谢谢。但是,这是一个虚拟的例子,如果我无法访问类A实现,因为它在导入的模块中,我该怎么办? – Albert

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

在你的第二个例子,你的问题是self你一起传递是B一个实例,而不是A一个实例,因此,当您尝试调用self.f你打电话B.f

不幸的是,你看到的行为实际上是OO编程应该工作。你为解决这个问题所做的任何事情都会对OO模式产生一些影响。这可能是比使用的mangling更加明确,但并不一定是另一种选择“真正的递归”,将沿着你想递归函数传:

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

这可能不是这可能的最佳方式写出来,但我认为它可以实现这个想法。您可以交替尝试从B.f的呼叫中传入A.f

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) 
+0

“if x = None:”should be“if x == None:”or better still“如果x是None:”。 – awatts

+0

@awatts:固定但是这个评论太短。 – SingleNegationElimination