Java und C ++ erfordern, dass ein Basisklassenkonstruktor aufgrund des Speicherlayouts aufgerufen wird.
Wenn Sie eine Klasse BaseClass
mit einem Mitglied field1
haben und eine neue Klasse erstellen SubClass
, die ein Mitglied hinzufügt field2
, SubClass
enthält eine Instanz von Platz für field1
und field2
. BaseClass
Zum Ausfüllen benötigen Sie einen Konstruktor von field1
, es sei denn, Sie benötigen alle ererbenden Klassen, um BaseClass
die Initialisierung in ihren eigenen Konstruktoren zu wiederholen . Und wenn field1
es privat ist, kann das Erben von Klassen nicht initialisiert werden field1
.
Python ist nicht Java oder C ++. Alle Instanzen aller benutzerdefinierten Klassen haben dieselbe 'Form'. Sie sind im Grunde nur Wörterbücher, in die Attribute eingefügt werden können. Bevor eine Initialisierung durchgeführt wurde, sind alle Instanzen aller benutzerdefinierten Klassen fast genau gleich . Sie sind nur Orte zum Speichern von Attributen, die noch keine gespeichert haben.
Daher ist es für eine Python-Unterklasse durchaus sinnvoll, ihren Basisklassenkonstruktor nicht aufzurufen. Es könnte einfach die Attribute selbst hinzufügen, wenn es wollte. Es ist kein Platz für eine bestimmte Anzahl von Feldern für jede Klasse in der Hierarchie reserviert, und es gibt keinen Unterschied zwischen einem Attribut, das durch Code aus einer BaseClass
Methode hinzugefügt wurde, und einem Attribut, das durch Code aus einer SubClass
Methode hinzugefügt wurde .
Wenn, wie üblich, SubClass
tatsächlich alle BaseClass
Invarianten eingerichtet werden sollen, bevor die eigene Anpassung vorgenommen wird, können Sie diese einfach aufrufen BaseClass.__init__()
(oder verwenden super
, aber das ist kompliziert und hat manchmal eigene Probleme). Aber das musst du nicht. Und Sie können es vorher oder nachher oder mit verschiedenen Argumenten tun. Zur Hölle, wenn Sie wollten, könnten Sie das BaseClass.__init__
von einer anderen Methode ganz aufrufen als __init__
; Vielleicht haben Sie eine bizarre Sache mit der faulen Initialisierung.
Python erreicht diese Flexibilität, indem es die Dinge einfach hält. Sie initialisieren Objekte, indem Sie eine __init__
Methode schreiben , die Attribute festlegt self
. Das ist es. Es verhält sich genau wie eine Methode, weil es genau eine Methode ist. Es gibt keine anderen seltsamen und nicht intuitiven Regeln für Dinge, die zuerst erledigt werden müssen, oder für Dinge, die automatisch passieren, wenn Sie keine anderen Dinge tun. Der einzige Zweck, dem es dienen muss, ist ein Hook, der während der Objektinitialisierung ausgeführt wird, um anfängliche Attributwerte festzulegen, und genau das tut es. Wenn Sie möchten, dass es etwas anderes tut, schreiben Sie dies explizit in Ihren Code.
__init__
Methode zu erben , und vielleicht sogar automatisch nach Unterklassen suchen und diese dekorieren.