Eu estou acostumado que no Objective-C eu tenho essa construção:
- (void)init {
if (self = [super init]) {
// init class
}
return self;
}
O Python também deve chamar a implementação da classe pai __init__
?
class NewClass(SomeOtherClass):
def __init__(self):
SomeOtherClass.__init__(self)
# init class
Isso também é verdadeiro / falso para __new__()
e__del__()
?
Edit: Há uma pergunta muito semelhante: Herança e Substituição __init__
em Python
python
oop
superclass
Georg Schölly
fonte
fonte
object
foi um erro de digitação. Mas agora você nem sequer tem osuper
título da sua pergunta.Respostas:
No Python, chamar a superclasse '
__init__
é opcional. Se você chamá-lo, também é opcional usar osuper
identificador ou nomear explicitamente a superclasse:No caso de um objeto, a chamada do super método não é estritamente necessária, pois o super método está vazio. O mesmo para
__del__
.Por outro lado, pois
__new__
, você deve realmente chamar o super método e usar seu retorno como o objeto recém-criado - a menos que queira explicitamente retornar algo diferente.fonte
[super init]
, seria mais comum. Apenas um pensamento especulativo; a super construção no Python 2.x é um pouco estranha para mim.Se você precisar que algo de super
__init__
seja feito além do que está sendo feito na classe atual,__init__,
você deve chamá-lo você mesmo, pois isso não acontecerá automaticamente. Mas se você não precisa de nada do super,__init__,
não precisa chamá-lo. Exemplo:__del__
é da mesma maneira (mas desconfie de confiar em__del__
finalizar - considere fazê-lo através da instrução with).Eu raramente uso
__new__.
faço toda a inicialização em__init__.
fonte
super(D,self).__init__()
Na resposta de Anon:
"Se você precisa fazer algo com super,
__init__
além do que está sendo feito na classe atual__init__
, você deve chamá-lo você mesmo, pois isso não acontecerá automaticamente"É incrível: ele está expondo exatamente o contrário do princípio da herança.
Não é que "algo do super
__init__
(...) não aconteça automaticamente" , é que isso aconteceria automaticamente, mas isso não acontece porque a classe base '__init__
é substituída pela definição dos clas derivados__init__
Então, por que definir uma classe derivada '
__init__
, uma vez que substitui o que se destina quando alguém recorre à herança?É porque é necessário definir algo que NÃO é feito na classe base '
__init__
, e a única possibilidade de obter isso é colocar sua execução em uma__init__
função de classe derivada' .Em outras palavras, é preciso algo na classe base '
__init__
além do que seria feito automaticamente na classe base'__init__
se esta última não fosse substituída.NÃO é o contrário.
Então, o problema é que as instruções desejadas presentes na classe base '
__init__
não são mais ativadas no momento da instanciação. Para compensar essa inativação, é necessário algo especial: chamar explicitamente a classe base '__init__
, para MANTER , NÃO ADICIONAR, a inicialização executada pela classe base'__init__
. É exatamente o que é dito no documento oficial:Essa é toda a história:
quando o objetivo é manter a inicialização executada pela classe base, que é pura herança, nada de especial é necessário, é preciso apenas evitar definir uma
__init__
função na classe derivadaquando o objetivo é SUBSTITUIR a inicialização realizada pela classe base,
__init__
deve ser definida na classe derivadaquando o objetivo é adicionar processos à inicialização executada pela classe base, uma classe derivada '
__init__
deve ser definida, compreendendo uma chamada explícita à classe base__init__
O que me surpreende no post de Anon não é apenas o fato de ele expressar o contrário da teoria da herança, mas o fato de cinco caras terem passado por isso aprovadas sem fazer barba e, além disso, não havia ninguém para reagir em dois anos. um tópico cujo assunto interessante deve ser lido com relativa frequência.
fonte
Editar : (após a alteração do código)
Não há como dizer se você precisa ou não chamar os pais
__init__
(ou qualquer outra função). A herança obviamente funcionaria sem essa ligação. Tudo depende da lógica do seu código: por exemplo, se tudo o que você__init__
faz na classe pai, você pode simplesmente pular a classe filho__init__
completo.considere o seguinte exemplo:
fonte
Não há regra rígida e rápida. A documentação para uma classe deve indicar se as subclasses devem chamar o método da superclasse. Às vezes, você deseja substituir completamente o comportamento da superclasse e, outras vezes, aumentá-lo - ou seja, chame seu próprio código antes e / ou depois de uma chamada de superclasse.
Atualização: a mesma lógica básica se aplica a qualquer chamada de método. Às vezes, os construtores precisam de consideração especial (pois geralmente configuram o estado que determina o comportamento) e os destruidores, porque são paralelos aos construtores (por exemplo, na alocação de recursos, por exemplo, conexões com o banco de dados). Mas o mesmo pode se aplicar, por exemplo, ao
render()
método de um widget.Atualização adicional: O que é o OPP? Você quer dizer POO? Não - uma subclasse geralmente precisa saber algo sobre o design da superclasse. Não os detalhes da implementação interna - mas o contrato básico que a superclasse possui com seus clientes (usando classes). Isso não viola os princípios de POO de forma alguma. É por isso que
protected
é um conceito válido no OOP em geral (embora não, é claro, no Python).fonte
OMI, você deve chamá-lo. Se sua superclasse é
object
, você não deveria, mas em outros casos, acho excepcional não chamá-lo. Como já foi respondido por outras pessoas, é muito conveniente que sua classe nem precise se substituir__init__
, por exemplo, quando não possui um estado interno (adicional) para inicializar.fonte
Sim, você sempre deve chamar a classe base
__init__
explicitamente como uma boa prática de codificação. Esquecer de fazer isso pode causar problemas sutis ou erros de tempo de execução. Isso é verdade mesmo se__init__
não houver parâmetros. Isso é diferente de outras linguagens em que o compilador implicitamente chamaria o construtor da classe base para você. Python não faz isso!O principal motivo para sempre chamar a classe base
_init__
é que a classe base normalmente pode criar variável de membro e inicializá-la com os padrões. Portanto, se você não chamar init da classe base, nada desse código seria executado e você terminaria com a classe base que não possui variáveis de membro.Exemplo :
Isso imprime ..
Execute este código .
fonte