Java y C ++ requieren que se llame a un constructor de clase base debido al diseño de la memoria.
Si tiene una clase BaseClass
con un miembro field1
y crea una nueva clase SubClass
que agrega un miembro field2
, entonces una instancia de SubClass
contiene espacio para field1
y field2
. Necesita un constructor de BaseClass
para completar field1
, a menos que requiera que todas las clases heredadas repitan BaseClass
la inicialización en sus propios constructores. Y si field1
es 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 BaseClass
método y un atributo agregado por código de un SubClass
método.
Si, como es común, en SubClass
realidad quiere tener todos BaseClass
los 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.