Ich bin es gewohnt, dass ich in Objective-C dieses Konstrukt habe:
- (void)init {
if (self = [super init]) {
// init class
}
return self;
}
Sollte Python auch die Implementierung der übergeordneten Klasse aufrufen __init__
?
class NewClass(SomeOtherClass):
def __init__(self):
SomeOtherClass.__init__(self)
# init class
Ist das auch wahr / falsch für __new__()
und __del__()
?
Bearbeiten: Es gibt eine sehr ähnliche Frage: Vererbung und Überschreiben __init__
in Python
python
oop
superclass
Georg Schölly
quelle
quelle
object
ein Tippfehler war. Aber jetzt haben Sie nicht einmal densuper
Titel, auf den sich Ihre Frage bezieht.Antworten:
In Python ist das Aufrufen der Superklasse
__init__
optional. Wenn Sie es aufrufen, ist es auch optional, ob Sie densuper
Bezeichner verwenden oder die Superklasse explizit benennen möchten:Im Falle eines Objekts ist das Aufrufen der Super-Methode nicht unbedingt erforderlich, da die Super-Methode leer ist. Gleiches gilt für
__del__
.Andererseits
__new__
sollten Sie in der Tat die Super-Methode aufrufen und ihre Rückgabe als neu erstelltes Objekt verwenden - es sei denn, Sie möchten ausdrücklich etwas anderes zurückgeben.quelle
[super init]
, wäre es üblicher. Nur ein spekulativer Gedanke; Das Superkonstrukt in Python 2.x ist für mich etwas umständlich.Wenn Sie
__init__
zusätzlich zu dem, was in der aktuellen Klasse getan wird, etwas von Super's tun__init__,
müssen, müssen Sie es selbst nennen, da dies nicht automatisch geschieht. Aber wenn Sie nichts von Super__init__,
brauchen, müssen Sie es nicht anrufen. Beispiel:__del__
ist der gleiche Weg (aber seien Sie vorsichtig, wenn Sie sich__del__
für die Finalisierung darauf verlassen - erwägen Sie dies stattdessen über die with-Anweisung).Ich benutze selten
__new__.
die gesamte Initialisierung in__init__.
quelle
super(D,self).__init__()
In Anons Antwort:
"Wenn Sie
__init__
zusätzlich zu dem, was in der aktuellen Klasse getan wird, etwas von Super's tun__init__
müssen, müssen Sie es selbst nennen, da dies nicht automatisch geschieht."Es ist unglaublich: Er formuliert genau das Gegenteil des Erbprinzips.
Es ist nicht so, dass "etwas von Super
__init__
(...) nicht automatisch passiert" , es ist so, dass es automatisch passieren würde, aber es passiert nicht, weil die Basisklasse '__init__
durch die Definition der abgeleiteten Klassen überschrieben wird__init__
Warum also eine abgeleitete Klasse definieren
__init__
, da sie überschreibt, was angestrebt wird, wenn jemand auf Vererbung zurückgreift ?Das liegt daran, dass man etwas definieren muss, das NICHT in der Basisklasse ausgeführt wird
__init__
, und die einzige Möglichkeit, dies zu erreichen, besteht darin, seine Ausführung in eine abgeleitete Klassenfunktion zu setzen__init__
.Mit anderen Worten, man braucht etwas in der Basisklasse "
__init__
zusätzlich zu dem, was automatisch in der Basisklasse gemacht wird",__init__
wenn diese nicht überschrieben würde.NICHT das Gegenteil.
Dann besteht das Problem darin, dass die gewünschten Anweisungen, die in der Basisklasse 'vorhanden
__init__
sind, zum Zeitpunkt der Instanziierung nicht mehr aktiviert werden. Um diese Inaktivierung auszugleichen, ist etwas Besonderes erforderlich: explizites Aufrufen der Basisklasse '__init__
, um die von der Basisklasse durchgeführte Initialisierung beizubehalten , NICHT ZU HINZUFÜGEN'__init__
. Genau das steht im offiziellen Dokument:Das ist die ganze Geschichte:
Wenn das Ziel darin besteht, die von der Basisklasse durchgeführte Initialisierung, dh die reine Vererbung, beizubehalten, ist nichts Besonderes erforderlich. Es muss lediglich vermieden werden, eine
__init__
Funktion in der abgeleiteten Klasse zu definierenWenn das Ziel darin besteht, die von der Basisklasse durchgeführte Initialisierung zu ERSETZEN,
__init__
muss sie in der abgeleiteten Klasse definiert werdenWenn das Ziel darin besteht, Prozesse zu der von der Basisklasse durchgeführten Initialisierung hinzuzufügen, muss eine abgeleitete Klasse
__init__
definiert werden, die einen expliziten Aufruf der Basisklasse umfasst__init__
Was ich an dem Posten von Anon erstaunlich finde, ist nicht nur, dass er das Gegenteil der Vererbungstheorie zum Ausdruck bringt, sondern dass 5 Leute an diesem Upvoted vorbeigegangen sind, ohne ein Haar zu drehen, und außerdem gab es in 2 Jahren niemanden, der darauf reagierte ein Thread, dessen interessantes Thema relativ oft gelesen werden muss.
quelle
Bearbeiten : (nach der Codeänderung)
Wir können Ihnen nicht sagen, ob Sie die Ihrer Eltern
__init__
(oder eine andere Funktion) aufrufen müssen oder nicht . Vererbung würde offensichtlich ohne einen solchen Anruf funktionieren. Es hängt alles von der Logik Ihres Codes ab: Wenn Sie__init__
beispielsweise alles in der übergeordneten Klasse erledigen, können Sie die untergeordnete Klasse einfach ganz überspringen__init__
.Betrachten Sie das folgende Beispiel:
quelle
Es gibt keine feste Regel. In der Dokumentation für eine Klasse sollte angegeben werden, ob Unterklassen die Oberklassenmethode aufrufen sollen. Manchmal möchten Sie das Verhalten von Oberklassen vollständig ersetzen und zu anderen Zeiten erweitern - dh Ihren eigenen Code vor und / oder nach einem Aufruf von Oberklassen aufrufen.
Update: Die gleiche Grundlogik gilt für jeden Methodenaufruf. Konstruktoren müssen manchmal besonders berücksichtigt werden (da sie häufig einen verhaltensbestimmenden Zustand einrichten) und Destruktoren, da sie parallele Konstruktoren sind (z. B. bei der Zuweisung von Ressourcen, z. B. Datenbankverbindungen). Das Gleiche gilt beispielsweise beispielsweise für die
render()
Methode eines Widgets.Weiteres Update: Was ist das OPP? Meinst du OOP? Nein - eine Unterklasse muss oft etwas über das Design der Oberklasse wissen . Nicht die internen Implementierungsdetails - sondern der Grundvertrag, den die Oberklasse mit ihren Kunden hat (unter Verwendung von Klassen). Dies verstößt in keiner Weise gegen die OOP-Prinzipien. Deshalb
protected
ist ein gültiges Konzept in OOP im Allgemeinen (obwohl natürlich nicht in Python).quelle
IMO, du solltest es nennen. Wenn Ihre Superklasse ist
object
, sollten Sie nicht, aber in anderen Fällen denke ich, dass es außergewöhnlich ist, es nicht zu nennen. Wie bereits von anderen beantwortet, ist es sehr praktisch, wenn Ihre Klasse sich nicht einmal selbst überschreiben__init__
muss, beispielsweise wenn sie keinen (zusätzlichen) internen Status zum Initialisieren hat.quelle
Ja, Sie sollten die Basisklasse immer
__init__
explizit als gute Codierungspraxis aufrufen . Wenn Sie dies vergessen, kann dies zu subtilen Problemen oder Laufzeitfehlern führen. Dies gilt auch dann, wenn__init__
keine Parameter verwendet werden. Dies ist anders als in anderen Sprachen, in denen der Compiler implizit den Basisklassenkonstruktor für Sie aufruft. Python macht das nicht!Der Hauptgrund für den ständigen Aufruf der Basisklasse
_init__
besteht darin, dass die Basisklasse normalerweise eine Mitgliedsvariable erstellt und diese auf Standardwerte initialisiert. Wenn Sie also nicht die Basisklasse init aufrufen, wird kein Code ausgeführt, und Sie erhalten eine Basisklasse ohne Mitgliedsvariablen.Beispiel :
Dies druckt ..
Führen Sie diesen Code aus .
quelle