Chamar o método de uma classe pai da classe filho?

608

Ao criar uma hierarquia de objetos simples em Python, eu gostaria de poder invocar métodos da classe pai de uma classe derivada. No Perl e Java, há uma palavra-chave para this ( super). No Perl, eu devo fazer isso:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

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

Em Python, parece que eu tenho que nomear explicitamente a classe pai do filho. No exemplo acima, eu teria que fazer algo parecido Foo::frotz().

Isso não parece certo, pois esse comportamento dificulta a criação de hierarquias profundas. Se as crianças precisarem saber que classe definiu um método herdado, todos os tipos de problemas de informação serão criados.

Isso é uma limitação real em python, uma lacuna no meu entendimento ou em ambos?

jjohn
fonte
3
Eu acho que o nome da classe dos pais não é uma idéia tão ruim. Pode ajudar quando a classe filho herda de mais de um pai, desde que você nomeie explicitamente a classe pai.
7
Embora uma opção para nomear uma classe não seja uma má idéia, ser forçado a fazê-lo certamente é.
Johndodo 9/07
Esteja ciente das mudanças na super manipulação entre Python 2 e Python 3 https://www.python.org/dev/peps/pep-3135/ . Nomear a classe não é mais necessário (embora ainda possa ser uma idéia divina, pelo menos algumas vezes).
jwpfox

Respostas:

737

Sim, mas apenas com classes de novo estilo . Use a super()função:

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)
Adam Rosenfield
fonte
53
Você também não pode "retornar Bar.baz (self, arg)"? Se sim, qual seria melhor?
15
Sim, você pode, mas o OP estava perguntando como fazer isso sem nomear explicitamente a superclasse no site da chamada (Bar, neste caso).
30511 Adam Rosenfield
7
super () é estranho com herança múltipla. Chama para a próxima classe. Essa pode ser a classe pai ou pode ser uma classe completamente não relacionada que aparece em outro lugar na hierarquia.
Steve Jessop
6
Eu uso o Python 2.x e recebo "Erro: deve ser do tipo, não classobj" quando faço isso #
Chris F
28
A sintaxe super(Foo, self)é correta para o Python 2.x? No Python 3.x, o super()preferido é correto?
Trevor Boyd Smith
144

O Python também tem super :

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

Retorne um objeto proxy que delega chamadas de método a uma classe pai ou irmã do tipo. Isso é útil para acessar métodos herdados que foram substituídos em uma classe. A ordem de pesquisa é igual à usada por getattr (), exceto que o próprio tipo é ignorado.

Exemplo:

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()
Jay
fonte
7
Melhor exemplo do que o de Adam, porque você demonstrou o uso de uma classe de novo estilo com a classe base de objeto. Faltando apenas o link para novas classes de estilo.
Samuel
83
ImmediateParentClass.frotz(self)

ficará bem, se a classe pai imediata frotzse definiu ou a herdou. superé necessário apenas para o suporte adequado à herança múltipla (e funciona apenas se todas as classes o usarem corretamente). Em geral, ele AnyClass.whateverirá procurar whatevernos AnyClassancestrais se AnyClassnão o definir / substituir, e isso vale para "classe filho chamando o método dos pais" como para qualquer outra ocorrência!

Alex Martelli
fonte
Isso exige que o ImmediateParentClass também esteja presente no escopo para que essa instrução seja executada. Apenas importar o objeto de um módulo não ajudará.
Tushar Vazirani
e se for um método de classe?
Shiplu Mokaddim 03/04/19
@TusharVazirani se a classe pai é imediata parent, está no escopo de toda a classe, não é?
Yaroslav Nikitenko
1
@YaroslavNikitenko Estou falando sobre a importação de uma instância, não da classe.
Tushar Vazirani
1
@TusharVazirani agora eu entendo, obrigado. Eu estava pensando em chamar do método da classe atual (como foi declarado pelo OP).
Yaroslav Nikitenko
75

O Python 3 possui uma sintaxe diferente e mais simples para chamar o método pai.

Se a Fooclasse herda de Bar, então from Bar.__init__pode ser invocado de Foovia super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)
Arun Ghosh
fonte
5
É bom ouvir que o python 3 tem uma solução melhor. A pergunta vem do python 2.X. Obrigado pela sugestão embora.
jjohn
46

Muitas respostas explicaram como chamar um método do pai que foi substituído no filho.

Contudo

"como você chama o método de uma classe pai da classe filho?"

também pode significar apenas:

"como você chama métodos herdados?"

Você pode chamar métodos herdados de uma classe pai, como se fossem métodos da classe filho, desde que não tenham sido substituídos.

por exemplo, em 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"

Sim, isso pode ser bastante óbvio, mas eu sinto que, sem apontar isso, as pessoas podem deixar esse segmento com a impressão de que você precisa pular coisas ridículas apenas para acessar métodos herdados em python. Especialmente porque essa pergunta é altamente avaliada em pesquisas sobre "como acessar o método de uma classe pai em Python", e o OP é escrito da perspectiva de alguém novo no python.

Eu achei: https://docs.python.org/3/tutorial/classes.html#inheritance útil para entender como você acessa métodos herdados.

Ben
fonte
@gizzmole em que situação isso não funciona? É um prazer adicionar quaisquer advertências ou avisos relevantes, mas não consegui descobrir como o link que você postou foi relevante para esta resposta.
Ben
@ Ben Desculpe, eu não li sua resposta com atenção suficiente. Esta resposta não responde à pergunta sobre como sobrecarregar funções, mas responde a uma pergunta diferente. Eu apaguei meu comentário inicial.
precisa saber é o seguinte
ah ah @gizzmole, não se preocupe. Percebo que essa resposta não se aplica a funções de sobrecarga, no entanto, a pergunta não menciona explicitamente sobrecarga (embora o exemplo perl dado mostre um caso de sobrecarga). A grande maioria das outras respostas cobre a sobrecarga - esta aqui está para aquelas pessoas que não precisam dela.
Ben
@ Ben e se eu quiser chamar B (). Baz () de outra classe chamada 'C' usando vars definidos em C ?. Eu tentei fazer B (). Baz () na classe C, onde self.string é outro val. Ele me deu nenhum, quando executado
Joey
@ joey Não sei ao certo o que você está tentando fazer ou se está dentro do escopo desta pergunta. String é uma variável local - a configuração self.stringnão fará nada. No entanto, na classe C você ainda pode ligarB().bar(string)
Ben
27

Aqui está um exemplo do 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
yesnik
fonte
Este não é um mau exemplo? Eu acredito que não é realmente seguro de usar Super menos que toda a sua hierarquia é classes "novo estilo" e corretamente chamando Super init () ().
Jaykul
14

Também existe um super () em Python. É um pouco instável, por causa das classes de estilo antigo e novo do Python, mas é bastante comum, por exemplo, nos construtores:

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

Eu recomendaria usar CLASS.__bases__ algo assim

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()
Joran Beasley
fonte
1
Lembre-se de que, como você pode ver pelo volume de referências a super aqui, as pessoas são realmente relutantes em usar bases, a menos que você esteja fazendo algo realmente profundo. Se você não gosta de super , veja mro . Tomar a primeira entrada no mro é mais seguro do que rastrear qual entrada nas bases usar. A herança múltipla no Python verifica certas coisas para trás e outras para a frente, deixando a linguagem para descontrair o processo.
precisa saber é o seguinte
5

Também existe um super () em python.

Exemplo de como um método de superclasse é chamado de um método de subclasse

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 exemplo é semelhante ao explicado acima.No entanto, há uma diferença que super não possui argumentos passados ​​para ele.Este código acima é executável na versão python 3.4.

kkk
fonte
3

Neste exemplo cafec_paramé uma classe base (classe pai) e abcé uma classe filho. abcchama o AWCmétodo na classe 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())

Resultado

56

56

56
Khan
fonte
2

No Python 2, não tive muita sorte com o super (). Eu usei a resposta do jimifiki neste tópico SO, como se referir a um método pai em python? . Em seguida, adicionei meu toque pessoal, que acho que é uma melhoria na usabilidade (especialmente se você tiver nomes de classe longos).

Defina a classe base em um módulo:

 # myA.py

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

Em seguida, importe a classe para outros módulos as parent:

# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'
BuvinJ
fonte
2
Você tem que usar class A(object): em vez de class A(): seguida super () irá funcionar
blndev
Não tenho certeza se sigo. Você quer dizer na definição da classe? Obviamente, você deve indicar que uma classe tem um pai ou mãe de alguma forma, a fim de pensar que você poderia se referir a um pai ou mãe! Desde que eu publiquei isso há 9 meses, estou um pouco confuso nos detalhes, mas acho que quis dizer que os exemplos de Arun Ghosh, lawrence, kkk etc. não são aplicáveis ​​no Py 2.x. Em vez disso, aqui está um método que funciona e uma maneira fácil de consultar o pai, para que fique um pouco mais claro o que você está fazendo. (como a utilização de 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()
maryam mehboob
fonte
-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()
RAVIKUMAR RACHA
fonte
2
Bem-vindo ao stackoverflow. Esta pergunta já foi respondida em detalhes há quase dez anos, a resposta aceita e amplamente votada, e sua resposta não adiciona nada de novo. Você pode tentar responder a perguntas mais recentes (e de preferência sem resposta). Como uma observação lateral, há um botão no editor para aplicar a formatação correta do código.
bruno desthuilliers
-24

Este é um método mais abstrato:

super(self.__class__,self).baz(arg)
user806071
fonte
15
self .__ class__ não funciona bem com super, já que self é sempre a instância e sua classe é sempre a classe da instância. Isto significa que se você usar super (self .__ class__ .. em uma classe e essa classe é herdada, não vai funcionar mais.
xitrium
16
Apenas para enfatizar, NÃO USE ESTE CÓDIGO. Ele derrota todo o objetivo de super (), que é atravessar corretamente o MRO.
Eevee
1
stackoverflow.com/a/19257335/419348 disse por que não ligar super(self.__class__, self).baz(arg).
precisa saber é o seguinte