Java e C ++ richiedono che venga chiamato un costruttore di classe base a causa del layout di memoria.
Se hai una classe BaseClass
con un membro field1
e crei una nuova classe SubClass
che aggiunge un membro field2
, un'istanza di SubClass
contiene spazio per field1
e field2
. È necessario BaseClass
compilare un costruttore field1
, a meno che non sia necessario che tutte le classi ereditarie ripetano BaseClass
l'inizializzazione nei propri costruttori. E se field1
è privato, l'ereditarietà delle classi non può essere inizializzata field1
.
Python non è Java o C ++. Tutte le istanze di tutte le classi definite dall'utente hanno la stessa "forma". Sono fondamentalmente solo dizionari in cui è possibile inserire attributi. Prima di qualsiasi inizializzazione, tutte le istanze di tutte le classi definite dall'utente sono quasi identiche ; sono solo luoghi in cui archiviare attributi che non sono ancora stati archiviati.
Quindi ha perfettamente senso che una sottoclasse Python non chiami il suo costruttore di classe base. Potrebbe semplicemente aggiungere gli attributi stessi se lo desiderasse. Non c'è spazio riservato per un determinato numero di campi per ogni classe nella gerarchia e non c'è differenza tra un attributo aggiunto dal codice da un BaseClass
metodo e un attributo aggiunto dal codice da un SubClass
metodo.
Se, come è comune, in SubClass
realtà vuole avere tutti BaseClass
gli invarianti impostati prima che continui a fare la propria personalizzazione, allora sì, puoi semplicemente chiamare BaseClass.__init__()
(o utilizzare super
, ma è complicato e ha i suoi problemi a volte). Ma non devi. E puoi farlo prima, o dopo, o con diversi argomenti. Inferno, se volevi, potresti chiamare il BaseClass.__init__
da un altro metodo interamente di __init__
; forse hai qualcosa di bizzarro inizializzazione pigra in corso.
Python raggiunge questa flessibilità mantenendo le cose semplici. Inizializzi gli oggetti scrivendo un __init__
metodo che imposta gli attributi self
. Questo è tutto. Si comporta esattamente come un metodo, perché è esattamente un metodo. Non ci sono altre regole strane e non intuitive sulle cose che devono essere fatte prima, o cose che accadranno automaticamente se non fai altre cose. L'unico scopo che deve servire è quello di essere un hook da eseguire durante l'inizializzazione dell'oggetto per impostare i valori degli attributi iniziali, e fa proprio questo. Se vuoi che faccia qualcos'altro, lo scrivi esplicitamente nel tuo codice.
__init__
metodo e forse anche cercare automaticamente le sottoclassi e decorarle.