2011-07-27 16 views
5

Cuando invoco el método recursivo de la clase base de la clase derivada, la llamada recursiva se realiza contra el método derivado, en lugar del método de la clase base. ¿Cómo puedo evitar ese sin modificar la implementación de la clase base (en la clase de ejemplo A)?anula el método recursivo en python

Aquí es un ejemplo

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

Tengo esta salida:

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) 

Gracias de antemano,

+1

Simplemente cambie el nombre de su función ... – JBernardo

Respuesta

4

Name mangling es la herramienta para este trabajo. Esto sería así en su caso:

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) 

Explicación de la documentación vinculada:

Cualquier identificador de la forma __spam (al menos dos subrayado iniciales, a lo sumo un guión detrás) textualmente reemplazado por _classname__spam, donde classname es el nombre de la clase actual con subrayado (s) principal (es) despojado (s).

+0

En general, es una buena idea proteger sus implementaciones y exponer sus interfaces. Esto conduce a una gran cantidad de 'def f (self, x): self._f (x)', pero hace que sea más fácil evitar estos problemas. – cwallenpoole

+3

Por lo general, es mejor evitar el mapeo de nombres si es posible. – awatts

+0

bien gracias. Pero ese es un ejemplo ficticio, ¿qué puedo hacer si no puedo acceder a la implementación de clase A porque está en el módulo importado? – Albert

0

Yo sugeriría cambiar el nombre de las clases base f método a un método privado llamado _f y tener que Recurse. A continuación, puede introducir un nuevo método f en la clase base que solo llama al _f. Entonces es libre de cambiar f en la subclase.

Sin embargo, puede no considerarse una buena práctica cambiar la firma del método en una subclase.

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

En el segundo ejemplo, el problema es que el self estás pasando junto es una instancia de B, no una instancia de A, por lo que cuando intenta llamar self.f que está llamando B.f.

Desafortunadamente, el comportamiento que está viendo es realmente como funciona la programación OO . Cualquier cosa que hagas para evitar esto va a ser una especie de hack alrededor del paradigma OO. Otra opción que podría ser más explícito que el uso de mangling, pero no es necesariamente "recursividad real", sería la de pasar a lo largo de la función que desea recursivo en:

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

Esto probablemente no es la mejor manera de que esto podría estar escrito, pero creo que hace entender la idea. Alternativamente, puede intentar pasar A.f desde su llamada en B.f.

1

Si no puede modificar la implementación de A, puede aprovechar la diferencia en las firmas de función.

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

"si x = None:" debe ser "si x == None:" o mejor aún "si x es None:". – awatts

+0

@awatts: corregido, pero este comentario es demasiado corto. – SingleNegationElimination

Cuestiones relacionadas