Java e C ++ exigem que um construtor de classe base seja chamado devido ao layout da memória.
Se você tem uma classe BaseClasscom um membro field1e cria uma nova classe SubClassque adiciona um membro field2, uma instância de SubClasscontém espaço para field1e field2. Você precisa de um construtor de BaseClasspreenchimento field1, a menos que exija que todas as classes herdadas repitam BaseClassa inicialização de seus próprios construtores. E se field1for 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 BaseClassmétodo e um atributo adicionado pelo código de um SubClassmétodo.
Se, como é comum, SubClassrealmente quer ter todos BaseClassos 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.