Java y C ++ requieren que se llame a un constructor de clase base debido al diseño de la memoria.
Si tiene una clase BaseClasscon un miembro field1y crea una nueva clase SubClassque agrega un miembro field2, entonces una instancia de SubClasscontiene espacio para field1y field2. Necesita un constructor de BaseClasspara completar field1, a menos que requiera que todas las clases heredadas repitan BaseClassla inicialización en sus propios constructores. Y si field1es privado, entonces las clases heredadas no pueden inicializarse field1.
Python no es Java o C ++. Todas las instancias de todas las clases definidas por el usuario tienen la misma 'forma'. Básicamente son solo diccionarios en los que se pueden insertar atributos. Antes de realizar cualquier inicialización, todas las instancias de todas las clases definidas por el usuario son casi exactamente iguales ; son solo lugares para almacenar atributos que aún no se almacenan.
Por lo tanto, tiene mucho sentido que una subclase de Python no llame a su constructor de clase base. Simplemente podría agregar los atributos en sí si quisiera. No hay espacio reservado para un número determinado de campos para cada clase en la jerarquía, y no hay diferencia entre un atributo agregado por código de un BaseClassmétodo y un atributo agregado por código de un SubClassmétodo.
Si, como es común, en SubClassrealidad quiere tener todos BaseClasslos invariantes configurados antes de continuar con su propia personalización, entonces sí, simplemente puede llamar BaseClass.__init__()(o usar super, pero eso es complicado y a veces tiene sus propios problemas). Pero no tienes que hacerlo. Y puede hacerlo antes, o después, o con diferentes argumentos. Demonios, si quisieras, puedes llamar BaseClass.__init__desde otro método completamente distinto de __init__; tal vez tengas algo extraño de inicialización perezosa.
Python logra esta flexibilidad manteniendo las cosas simples. Inicializa objetos escribiendo un __init__método que establece atributos en self. Eso es. Se comporta exactamente como un método, porque es exactamente un método. No hay otras reglas extrañas y poco intuitivas sobre las cosas que deben hacerse primero, o cosas que sucederán automáticamente si no haces otras cosas. El único propósito que debe cumplir es ser un gancho para ejecutar durante la inicialización del objeto para establecer los valores de los atributos iniciales, y lo hace. Si quiere que haga otra cosa, explícitamente escriba eso en su código.
__init__método, e incluso quizás buscar automáticamente subclases y decorarlas.