2011-07-27 65 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