2011-07-27 13 views
5

Kiedy wywołuję metodę rekurencyjną klasy bazowej z klasy pochodnej, wywołanie rekursywne jest wykonywane względem metody pochodnej, zamiast metody klasy bazowej. Jak mogę uniknąć tego bez modyfikowania implementacji klasy podstawowej (na przykład w klasie A)?Zastępowanie metody rekursywnej w pythoniu

Oto przykład

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

Mam tego wyjścia:

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) 

Dzięki z góry,

+1

Wystarczy zmienić nazwę swojej funkcji ... – JBernardo

Odpowiedz

4

Name mangling jest narzędziem do tego zadania. To będzie wyglądać tak w przypadku:

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) 

wyjaśnień od powiązanej dokumentacji:

Każdy identyfikator postaci __spam (przynajmniej dwie wiodące podkreślenia co najwyżej jeden wleczonego podkreślenie) jest tekstowo zastąpiony przez _classname__spam, gdzie nazwa_klasy jest bieżącą nazwą klasy z wiodącymi podkreślnikami (underscore) pozbawionymi.

+0

Tt jest ogólnie dobry pomysł, aby chronić swoje implementacje i narażać swoje interfejsy. Prowadzi to do wielu 'def f (self, x): self._f (x)', ale ułatwia to uniknięcie tych problemów. – cwallenpoole

+3

Wymazywanie nazwy jest zwykle najlepiej unikać, jeśli to możliwe. – awatts

+0

ok dzięki. Ale to jest fałszywy przykład, co mogę zrobić, jeśli nie mogę uzyskać dostępu do implementacji klasy A, ponieważ jest ona w importowanym module? – Albert

0

Proponuję zmienić nazwę klasy bazowej f metody prywatnej metody o nazwie _f i mieć to powtarzające się. Następnie możesz wprowadzić nową metodę f do klasy bazowej, która po prostu wywołuje _f. Następnie możesz zmienić f w podklasie.

Jednak nie można uznać za dobrą praktykę zmianę sygnatury metody w podklasie.

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

W drugim przykładzie, problem jest taki, że self jesteś przechodzącą wzdłuż jest instancją B nie instancją A, więc jeśli spróbujesz zadzwonić self.f dzwonisz B.f.

Niestety, zachowanie, które widzisz, jest tak naprawdę sposobem, w jaki programowanie OO powinno działać. Wszystko, co robisz, aby obejść ten problem, będzie trochę hackować wokół paradygmatu OO. Innym rozwiązaniem, które może być bardziej wyraźne niż przy użyciu maglowania, ale niekoniecznie jest „prawdziwy rekursji”, byłoby przejść funkcji chcesz recurse na:

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

To prawdopodobnie nie jest to najlepszy sposób mogłoby to być napisanym, ale myślę, że wpadł na ten pomysł. Możesz na przemian próbować przekazać A.f ze swojego połączenia w B.f.

1

Jeśli nie możesz zmodyfikować implementacji A, możesz skorzystać z różnicy w sygnaturach funkcji.

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

"jeśli x = brak:" powinno być "jeśli x == brak:" lub jeszcze lepiej ", jeśli x to brak:". – awatts

+0

@awatts: naprawiono, ale ten komentarz jest za krótki. – SingleNegationElimination

Powiązane problemy