¿Llamar al método de una clase principal desde la clase secundaria?


608

Al crear una jerarquía de objetos simple en Python, me gustaría poder invocar métodos de la clase primaria desde una clase derivada. En Perl y Java, hay una palabra clave para this ( super). En Perl, podría hacer esto:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

sub frotz {
   my $str = SUPER::frotz();
   return uc($str);
}

En Python, parece que tengo que nombrar la clase padre explícitamente desde el niño. En el ejemplo anterior, tendría que hacer algo como Foo::frotz().

Esto no parece correcto ya que este comportamiento dificulta la creación de jerarquías profundas. Si los niños necesitan saber qué clase definió un método heredado, entonces se crea todo tipo de dolor de información.

¿Es esta una limitación real en Python, un vacío en mi comprensión o ambos?


3
Creo que nombrar a la clase principal no es una mala idea. Puede ayudar cuando la clase secundaria hereda de más de un elemento primario, ya que usted nombra explícitamente la clase principal.

77
Si bien una opción para nombrar una clase no es una mala idea, verse obligado a hacerlo ciertamente lo es.
johndodo

Tenga en cuenta los cambios en el súper manejo entre Python 2 y Python 3 https://www.python.org/dev/peps/pep-3135/ . Nombrar la clase ya no es obligatorio (aunque puede ser una buena idea, al menos a veces).
jwpfox

Respuestas:


737

Sí, pero solo con clases de estilo nuevo . Usa la super()función:

class Foo(Bar):
    def baz(self, arg):
        return super().baz(arg)

Para python <3, use:

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)

53
¿No puedes hacer también "return Bar.baz (self, arg)"? Si es así, ¿cuál sería mejor?

15
Sí, puede, pero el OP preguntaba cómo hacerlo sin nombrar explícitamente la superclase en el sitio de la llamada (Bar, en este caso).
Adam Rosenfield el

77
super () es raro con herencia múltiple. Llama a la "próxima" clase. Esa podría ser la clase principal, o podría ser una clase completamente no relacionada que aparece en otra parte de la jerarquía.
Steve Jessop

66
Uso Python 2.x, y aparece "Error: debe ser tipo, no classobj" cuando hago esto
Chris F

28
La sintaxis super(Foo, self)es para Python 2.x ¿correcto? En Python 3.x, ¿ super()se prefiere el correcto?
Trevor Boyd Smith

144

Python también tiene super :

super(type[, object-or-type])

Devuelve un objeto proxy que delega llamadas de método a una clase de tipo padre o hermano. Esto es útil para acceder a métodos heredados que se han anulado en una clase. El orden de búsqueda es el mismo que el utilizado por getattr (), excepto que se omite el tipo en sí.

Ejemplo:

class A(object):     # deriving from 'object' declares A as a 'new-style-class'
    def foo(self):
        print "foo"

class B(A):
    def foo(self):
        super(B, self).foo()   # calls 'A.foo()'

myB = B()
myB.foo()

77
Mejor ejemplo que el de Adam porque demostraste usar una clase de estilo nuevo con la clase base de objeto. Solo falta el enlace a las clases de estilo nuevo.
Samuel

83
ImmediateParentClass.frotz(self)

estará bien, ya sea que la clase primaria inmediata se haya definido frotzo heredado. supersolo es necesario para el soporte adecuado de la herencia múltiple (y luego solo funciona si cada clase lo usa correctamente). En general, AnyClass.whateverbuscará whateveren AnyClasslos antepasados ​​si AnyClassno lo define / anula, ¡y esto es válido para el "método de los padres que llaman a la clase secundaria" como para cualquier otra ocurrencia!


Esto exige que ImmediateParentClass también esté presente en el alcance para que se ejecute esta declaración. Simplemente tener el objeto importado de un módulo no ayudará.
Tushar Vazirani

¿Qué pasa si es un método de clase?
Shiplu Mokaddim

@TusharVazirani si la clase principal es inmediata parent, está dentro del alcance de toda la clase, ¿no es así?
Yaroslav Nikitenko

1
@YaroslavNikitenko Estoy hablando de importar una instancia, no la clase.
Tushar Vazirani

1
@TusharVazirani ahora entiendo, gracias. Estaba pensando en llamar desde el método de la clase actual (como lo indicó el OP).
Yaroslav Nikitenko

75

Python 3 tiene una sintaxis diferente y más simple para llamar al método padre.

Si la Fooclase hereda de Bar, entonces Bar.__init__se puede invocar desde a Footravés de super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)

55
Es bueno escuchar que Python 3 tiene una mejor solución. La pregunta proviene de python 2.X. Gracias por la sugerencia sin embargo.
jjohn

46

Muchas respuestas han explicado cómo llamar a un método del padre que se ha anulado en el hijo.

sin embargo

"¿Cómo se llama el método de una clase principal desde la clase secundaria?"

También podría significar simplemente:

"¿Cómo se llaman los métodos heredados?"

Puede llamar a los métodos heredados de una clase principal como si fueran métodos de la clase secundaria, siempre que no se hayan sobrescrito.

Por ejemplo, en Python 3:

class A():
  def bar(self, string):
    print("Hi, I'm bar, inherited from A"+string)

class B(A):
  def baz(self):
    self.bar(" - called by baz in B")

B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"

Sí, esto puede ser bastante obvio, pero creo que sin señalar esto, las personas pueden dejar este hilo con la impresión de que tienes que saltar a través de aros ridículos solo para acceder a métodos heredados en Python. Especialmente porque esta pregunta tiene una alta calificación en las búsquedas de "cómo acceder al método de una clase primaria en Python", y el OP se escribe desde la perspectiva de alguien nuevo en python.

Encontré que: https://docs.python.org/3/tutorial/classes.html#inheritance es útil para comprender cómo accede a los métodos heredados.


@gizzmole, ¿en qué situación esto no funciona? Me complace agregar algunas advertencias o advertencias que sean relevantes, pero no pude entender cómo el enlace que publicó fue relevante para esta respuesta.
Ben

@Ben Lo siento, no leí tu respuesta con suficiente cuidado. Esta respuesta no responde la pregunta sobre cómo sobrecargar funciones, pero responde una pregunta diferente. Eliminé mi comentario inicial.
gizzmole

@gizzmole ah, no te preocupes. Me doy cuenta de que esta respuesta no se aplica a las funciones de sobrecarga, sin embargo, la pregunta no menciona explícitamente la sobrecarga (aunque el ejemplo de Perl dado muestra un caso de sobrecarga). La gran mayoría de las otras respuestas cubren la sobrecarga: esta está aquí para aquellas personas que no la necesitan.
Ben

@Ben, ¿y si quiero llamar a B (). Baz () desde otra clase llamada 'C' usando vars definidos en C ?. Intenté hacer B (). Baz () en la clase C, donde self.string es otro valor. No me dio ninguno, cuando
ejecuté

@joey No estoy seguro de lo que estás tratando de hacer, o si está dentro del alcance de esta pregunta. La cadena es una variable local: la configuración self.stringno hará nada. En la clase C, sin embargo, todavía podría llamarB().bar(string)
Ben

27

Aquí hay un ejemplo del uso de super () :

#New-style classes inherit from object, or from another new-style class
class Dog(object):

    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self):
        self.moves.append('walk')
        self.moves.append('run')

    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super(Superdog, self).moves_setup()
        self.moves.append('fly')

dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly']. 
#As you can see our Superdog has all moves defined in the base Dog class

¿No es este un mal ejemplo? Creo que no es realmente seguro usar Super a menos que toda su jerarquía tenga clases de "nuevo estilo" y llame correctamente a Super ().
Init

14

También hay un super () en Python. Es un poco raro, debido a las clases de estilo antiguo y nuevo de Python, pero se usa con bastante frecuencia, por ejemplo, en constructores:

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5

10

Yo recomendaría usar CLASS.__bases__ algo como esto

class A:
   def __init__(self):
        print "I am Class %s"%self.__class__.__name__
        for parentClass in self.__class__.__bases__:
              print "   I am inherited from:",parentClass.__name__
              #parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()

1
Tenga en cuenta que, como puede ver por el volumen de referencias a super aquí, la gente es realmente reacia a usar bases a menos que esté haciendo algo realmente profundo. Si no te gusta super , mira mro . Tomar la primera entrada en mro es más seguro que rastrear qué entrada en bases usar. La herencia múltiple en Python escanea ciertas cosas hacia atrás y otras hacia adelante, por lo que es más seguro dejar que el lenguaje desenrolle el proceso.
Jon Jay Obermark


5

También hay un super () en python.

Ejemplo de cómo se llama a un método de superclase desde un método de subclase

class Dog(object):
    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self,x):
        self.moves.append('walk')
        self.moves.append('run')
        self.moves.append(x)
    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super().moves_setup("hello world")
        self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves()) 

Este ejemplo es similar al explicado anteriormente. Sin embargo, hay una diferencia de que super no tiene ningún argumento pasado. Este código anterior es ejecutable en la versión Python 3.4.


3

En este ejemplo cafec_parames una clase base (clase primaria) y abces una clase secundaria. abcllama al AWCmétodo en la clase base.

class cafec_param:

    def __init__(self,precip,pe,awc,nmonths):

        self.precip = precip
        self.pe = pe
        self.awc = awc
        self.nmonths = nmonths

    def AWC(self):

        if self.awc<254:
            Ss = self.awc
            Su = 0
            self.Ss=Ss
        else:
            Ss = 254; Su = self.awc-254
            self.Ss=Ss + Su   
        AWC = Ss + Su
        return self.Ss


    def test(self):
        return self.Ss
        #return self.Ss*4

class abc(cafec_param):
    def rr(self):
        return self.AWC()


ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())

Salida

56

56

56

2

En Python 2, no tuve mucha suerte con super (). Utilicé la respuesta de jimifiki en este hilo SO, ¿cómo referirme a un método padre en python? . Luego, le agregué mi propio pequeño giro, lo que creo que es una mejora en la usabilidad (especialmente si tiene nombres de clase largos).

Defina la clase base en un módulo:

 # myA.py

class A():     
    def foo( self ):
        print "foo"

Luego importe la clase a otros módulos as parent:

# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'

2
Tienes que usar en class A(object): lugar de class A(): Entonces super () funcionará
blndev

No estoy seguro de seguirlo. ¿Quieres decir en la definición de la clase? ¡Obviamente, debe indicar que una clase tiene un padre de alguna manera para pensar que podría referirse a un padre! Desde que publiqué esto hace 9 meses, estoy un poco confuso en los detalles, pero creo que quise decir que los ejemplos de Arun Ghosh, Lawrence, KKK, etc. no son aplicables en Py 2.x. En cambio, aquí hay un método que funciona y una manera fácil de referirse a los padres para que sea un poco más claro lo que está haciendo. (como usar super)
BuvinJ

0
class department:
    campus_name="attock"
    def printer(self):
        print(self.campus_name)

class CS_dept(department):
    def overr_CS(self):
        department.printer(self)
        print("i am child class1")

c=CS_dept()
c.overr_CS()

-3
class a(object):
    def my_hello(self):
        print "hello ravi"

class b(a):
    def my_hello(self):
    super(b,self).my_hello()
    print "hi"

obj = b()
obj.my_hello()

2
Bienvenido a stackoverflow. Esta pregunta ya ha sido respondida en detalle hace casi diez años, la respuesta fue aceptada y ampliamente votada, y su respuesta no agrega nada nuevo. Es posible que desee intentar responder preguntas más recientes (y preferiblemente sin respuesta) en su lugar. Como nota al margen, hay un botón en el editor para aplicar el formato de código adecuado.
bruno desthuilliers

-24

Este es un método más abstracto:

super(self.__class__,self).baz(arg)

15
self .__ class__ no funciona bien con super ya que self es siempre la instancia y su clase es siempre la clase de la instancia. Esto significa que si usa super (self .__ class__ .. en una clase y esa clase se hereda, ya no funcionará.
Xitrium

16
Solo para enfatizar, NO USE ESTE CÓDIGO. Derrota todo el propósito de super (), que es atravesar correctamente el MRO.
Eevee

1
stackoverflow.com/a/19257335/419348 dijo por qué no llamarsuper(self.__class__, self).baz(arg) .
AechoLiu
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.