2010-05-16 11 views
13

considerar esta situación:Python: cómo inherite y anular

consigo un objeto de tipo A que tiene la función f. Es decir:

class A: 
    def f(self): 
     print 'in f' 
    def h(self): 
     print 'in h' 

y consigo una instancia de esta clase, pero quiero anular la función f sino para salvar el resto de la funcionalidad de A. Así que lo que estaba pensando era algo por el estilo:

class B(A): 
    def __init__(self, a): 
     #something here 
    .... 

    def f(self): 
     print 'in B->f' 

y el uso sería:

def main(a): 
    b = B(a) 
    b.f() #prints "in B->f" 
    b.h() #print "in h" 

Lo que yo quiero es una especie de copia constructor que recibe uno de los padres de la clase actual (A) y devuelve una instancia de esta clase (B).

¿Cómo se hace tal cosa? ¿Cómo se vería el método __init__?

Nota:: esta publicación ha sido editada por el póster original para incorporar los cambios sugeridos a continuación, razón por la cual algunas de las sugerencias parecen redundantes o incorrectas.

+0

¿Qué se supone que 'a' representa? – SilentGhost

+0

'a' es una instancia de' A' – Guy

+0

y ¿por qué lo necesitarías? – SilentGhost

Respuesta

8

¿Cómo se construye un objeto de la subclase B "basado en" una de clase A depende exclusivamente de cómo este último mantiene el estado , en su caso, y ¿cómo mejor llegar a ese estado y copiarlo. En su ejemplo, las instancias de A son apátridas, por lo tanto no hay absolutamente ningún trabajo que deba hacer en B 's '__init__'. En un ejemplo más típico, por ejemplo:

class A(object): 
    def __init__(self): 
    self._x = 23 
    self._y = 45 
    def f(self): 
     print 'in f,', self._x 
    def h(self): 
     print 'in h,', self._y 

el estado estaría en los dos atributos de instancia _x y _y, por lo que aquellos son lo que necesita copiar:

class B(A): 
    def __init__(self, a): 
     self._x = a._x 
     self._y = a._y 

    def f(self): 
     print 'in B->f,', self._x 

Este es el más común y enfoque normal, donde la subclase acepta e implementa directamente su dependencia del estado en la superclase, es muy sencillo y lineal.

Normalmente busca A 's aspectos estatales ejemplo, en A' '__init__' s, porque la mayoría del código Python normal, sencillo establece estado de la instancia en la inicialización (atributos podrían añadirse y se retira después, o incluso de código fuera de la el cuerpo de la clase, pero eso no es común y generalmente no es aconsejable).

Se es posible añadir un pequeño toque de "magia" (programación basada en la introspección), por ejemplo ..:

class B1(A): 
    def __init__(self, a): 
     try: s = a.__getstate__() 
     except AttributeError: s = a.__dict__ 
     try: self.__setstate__(s) 
     except AttributeError: self.__dict__.update(s) 

getstate es un método especial que las clases pueden definir - si lo hacen , se usa (p. ej., encurtido) para "obtener el estado" de sus instancias con fines de serialización (de lo contrario, se considera que el ejemplar de __dict__ es el "estado" de la instancia). Puede devolver un dict (en cuyo caso la llamada .update actualiza el estado self), pero también puede devolver cualquier otra cosa si la clase también define un __setstate__ que lo acepta (por lo que este código intenta esa ruta primero, antes de volver a caer en el posibilidad de actualización). Tenga en cuenta que en este caso de uso, uno o ambos métodos especiales se heredarían de A - No los definiría/anularía en B (a menos que haya objetivos más sutiles que se puedan lograr de esa manera, por supuesto ;-).

¿Vale la pena utilizar estas cuatro líneas de "magia" en lugar de las asignaciones simples que sugerí por primera vez? En su mayoría, no, la simplicidad es preferible. Pero si A hace algo especial o está sujeto a un código externo que altera su estado, esta solución puede ser más poderosa y general (eso es lo que está comprando al aceptar su complicación). Entonces, debes saber si el último caso se aplica (y luego "opta por las armas grandes" de los métodos especiales relacionados con el estado), o si A y sus instancias son "vainillas bastante normales", en cuyo caso yo recomendaría mucho recomendamos elegir simplicidad y claridad en su lugar.

+0

exactamente lo que estaba buscando. ¡Gracias! – Guy

+0

@Guy, de nada! –

+0

+1 - Lo más informativo que he leído hoy: "depende ... de cómo este último mantiene el estado y cómo ... lo copias" – deadly

5

Prueba esto:

class A: 
    def f(self): 
    print("in f") 

    def h(self): 
    print("in h") 

class B(A): 
    def f(self): 
    print("in B:f") 

def test(x): 
    x.f() 
    x.h() 

test(A()) 
test(B()) 

Nota, estoy usando Python 3, que es la razón de print tomando los argumentos entre paréntesis.

Salida:

in f 
in h 
in B:f 
in h 
+1

y ¿cómo es diferente del código de OP? Solo se olvidó de "sí mismo", parece. – SilentGhost

+0

por cierto, ¿qué significa que los métodos sean virtuales en python? –

+1

@Bunny Rabbit: Douglas significa 'virtual' como en' C++ ', donde tiene que definir explícitamente un método como' virtual' para que sea anulable. –

1

Es necesario poner el argumento self en la lista de argumentos para los métodos de instancia en Python.

Una vez que hayas hecho eso, simplemente funcionará, porque todos los métodos son virtuales en python.