Java e C ++ exigem que um construtor de classe base seja chamado devido ao layout da memória.
Se você tem uma classe BaseClass
com um membro field1
e cria uma nova classe SubClass
que adiciona um membro field2
, uma instância de SubClass
contém espaço para field1
e field2
. Você precisa de um construtor de BaseClass
preenchimento field1
, a menos que exija que todas as classes herdadas repitam BaseClass
a inicialização de seus próprios construtores. E se field1
for privado, as classes herdadas não poderão inicializar field1
.
Python não é Java ou C ++. Todas as instâncias de todas as classes definidas pelo usuário têm a mesma 'forma'. Eles são basicamente apenas dicionários nos quais os atributos podem ser inseridos. Antes de qualquer inicialização, todas as instâncias de todas as classes definidas pelo usuário são quase exatamente iguais ; são apenas lugares para armazenar atributos que ainda não estão sendo armazenados.
Portanto, faz sentido que uma subclasse Python não chame seu construtor de classe base. Apenas poderia adicionar os próprios atributos, se quisesse. Não há espaço reservado para um determinado número de campos para cada classe na hierarquia e não há diferença entre um atributo adicionado pelo código de um BaseClass
método e um atributo adicionado pelo código de um SubClass
método.
Se, como é comum, SubClass
realmente quer ter todos BaseClass
os invariantes configurados antes de fazer sua própria personalização, sim, você pode simplesmente ligar BaseClass.__init__()
(ou usar super
, mas isso é complicado e, às vezes, tem seus próprios problemas). Mas você não precisa. E você pode fazer isso antes, depois ou com argumentos diferentes. Inferno, se você quisesse, poderia chamar o BaseClass.__init__
de outro método inteiramente do que __init__
; talvez você tenha alguma coisa bizarra de inicialização lenta.
O Python consegue essa flexibilidade, mantendo as coisas simples. Você inicializa objetos escrevendo um __init__
método que define atributos self
. É isso aí. Ele se comporta exatamente como um método, porque é exatamente um método. Não há outras regras estranhas e não intuitivas sobre o que deve ser feito primeiro, ou o que acontecerá automaticamente se você não fizer outras coisas. O único objetivo que ele precisa servir é ser um gancho para executar durante a inicialização do objeto para definir valores de atributos iniciais, e é exatamente isso. Se você quiser fazer outra coisa, escreva explicitamente isso no seu código.
__init__
método e até mesmo procurar automaticamente subclasses e decorá-las.