Python-Konstruktoren und __init__

107

Warum werden Konstruktoren tatsächlich "Konstruktoren" genannt? Was ist ihr Zweck und wie unterscheiden sie sich von Methoden in einer Klasse?

Kann es auch mehr als einen __init__in einer Klasse geben? Ich habe folgendes versucht, kann jemand bitte das Ergebnis erklären?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Ist schließlich __init__ein Operator Overlader?

Arindam Roychowdhury
quelle
41
Technisch __init__ist ein Initialisierer . Der Python- Konstruktor ist __new__. Python verwendet die automatische zweiphasige Initialisierung - __new__gibt ein gültiges, aber (normalerweise) nicht ausgefülltes Objekt zurück (siehe boolein Gegenbeispiel), das es dann __init__automatisch aufgerufen hat. Dies vermeidet die Probleme, die Sprachen wie C ++ mit teilweise konstruierten Objekten haben - Sie haben nie eines in Python (obwohl es teilweise initialisiert sein kann). Sie müssen fast nie beide __new__und __init__eine Klasse überschreiben .
Tim Delaney
2
@ TimDelaney: Ich bin nicht sicher, was Sie mit teilweise konstruierten Objekten in C ++ meinen.
Sebastian Mach
11
@phresnel In C ++ ist der Typ des Objekts die Basisklasse (nicht die Unterklasse) im Basisklassenkonstruktor. Sie können keine virtuelle Methode im Basisklassenkonstruktor aufrufen und die Implementierung von der Unterklasse bereitstellen lassen. In Java können Sie eine Unterklassenmethode im Basisklassenkonstruktor aufrufen, aber die Unterklassenmitgliedsvariablen werden nach dem Basisklassenkonstruktor (und dem Methodenaufruf) automatisch initialisiert . In Sprachen mit zweiphasiger Initialisierung wie Python können Sie problemlos Methoden im Basisklasseninitialisierer aufrufen und die Unterklasse das Verhalten bereitstellen (oder überschreiben) lassen.
Tim Delaney
@ TimDelaney: Ah, danke für die Klarstellung.
Sebastian Mach
4
@ TimDelaney. Ich denke, dass Ihr Kommentar die akzeptierte Antwort ersetzen sollte.
Flamenco

Antworten:

114

In Python gibt es keine Funktionsüberladung, was bedeutet, dass Sie nicht mehrere Funktionen mit demselben Namen, aber unterschiedlichen Argumenten haben können.

In Ihrem Codebeispiel überladen Sie nicht __init__(). Was passiert ist, dass die zweite Definition den Namen erneut an die neue Methode bindet__init__ und die erste Methode unzugänglich macht.

In Bezug auf Ihre allgemeine Frage zu Konstruktoren ist Wikipedia ein guter Ausgangspunkt. Für Python-spezifische Dinge empfehle ich die Python-Dokumente .

NPE
quelle
Bedeutet dies auch, dass die Quelldatei nacheinander analysiert (interpretiert?) Wird? Kann ich sicher sein, dass die Funktion, die ich später definiert habe, die zuvor mit demselben Namen definierte überschreibt? :( mein Q klingt albern .. hätte es
wissen
4
@ 0xc0de: In Python sind Funktionsdefinitionen tatsächlich ausführbare Anweisungen und werden von oben nach unten ausgeführt, also ja.
NPE
1
@ 0xc0de Was tatsächlich passiert, ist, dass der Hauptteil der Klasse in seinem eigenen Namespace ausgeführt wird und dieser Namespace dann an die Metaklasse übergeben wird (zusammen mit dem Namen und den Basen). Funktionsdefinitionen erstellen dann nur eine Funktion mit dem angegebenen Körper und weisen sie ihrem Namen zu. Die letzte Aufgabe __init__ist, was in der Klasse endet.
Skyking
64

Warum werden Konstruktoren tatsächlich "Konstruktoren" genannt?

Der Konstruktor (benannt __new__) erstellt eine neue Instanz der Klasse und gibt sie zurück. Die C.__new__Klassenmethode ist also der Konstruktor für die Klasse C.

Die C.__init__Instanzmethode wird für eine bestimmte Instanz aufgerufen, nachdem sie erstellt wurde, um sie zu initialisieren, bevor sie an den Aufrufer zurückgegeben wird. Diese Methode ist also der Initialisierer für neue Instanzen von C.

Wie unterscheiden sie sich von Methoden in einer Klasse?

Wie in der offiziellen Dokumentation angegeben, __init__ wird nach dem Erstellen der Instanz aufgerufen . Andere Methoden erhalten diese Behandlung nicht.

Was ist ihr Zweck?

Der Zweck des Konstruktors C.__new__besteht darin, das benutzerdefinierte Verhalten während der Erstellung einer neuen CInstanz zu definieren .

Der Zweck des Initialisierers C.__init__besteht darin, die benutzerdefinierte Initialisierung jeder Instanz Cnach ihrer Erstellung zu definieren .

Mit Python können Sie beispielsweise Folgendes tun:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Wenn Sie jedoch möchten, dass jede Instanz Testein Attribut xvon 10 hat, können Sie diesen Code einfügen __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Jede Instanzmethode (eine Methode, die für eine bestimmte Instanz einer Klasse aufgerufen wird) empfängt die Instanz als erstes Argument. Dieses Argument wird herkömmlicherweise benannt self.

Klassenmethoden wie der Konstruktor __new__erhalten stattdessen die Klasse als erstes Argument.

Wenn Sie nun benutzerdefinierte Werte für das xAttribut wünschen , müssen Sie diesen Wert nur noch als Argument an Folgendes übergeben __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

Ich hoffe, dies wird Ihnen helfen, einige Zweifel auszuräumen, und da Sie bereits gute Antworten auf die anderen Fragen erhalten haben, werde ich hier aufhören :)

Rik Poggi
quelle
9

Klassen sind einfach Blaupausen, aus denen Objekte erstellt werden können. Der Konstruktor ist ein Code, der jedes Mal ausgeführt wird, wenn Sie ein Objekt erstellen. Daher ist es nicht sinnvoll, zwei Konstruktoren zu haben. Was passiert ist, dass der zweite den ersten überschreibt.

Normalerweise verwenden Sie sie, um Variablen für dieses Objekt wie folgt zu erstellen:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Sie können also ein Objekt aus dieser Klasse wie folgt erstellen:

>>> testobject = testing(5)

Das Testobjekt hat dann ein Objekt namens some_value5 in diesem Beispiel.

>>> testobject.some_value
5

Sie müssen jedoch nicht für jedes Objekt einen Wert festlegen, wie ich es in meinem Beispiel getan habe. Sie können auch Folgendes tun:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

dann ist der Wert von some_value 5 und Sie müssen ihn nicht festlegen, wenn Sie das Objekt erstellen.

>>> testobject = testing()
>>> testobject.some_value
5

Das >>> und ... in meinem Beispiel ist nicht das, was Sie schreiben. So würde es in Pyshell aussehen ...

Niclas Nilsson
quelle
Kein Problem, ich bin froh, dass es dir geholfen hat :)
Niclas Nilsson
1

Coonstruktoren werden automatisch aufgerufen, wenn Sie ein neues Objekt erstellen, wodurch das Objekt "konstruiert" wird. Der Grund, warum Sie mehr als ein Init haben können, ist, dass Namen nur Referenzen in Python sind und Sie jederzeit ändern können, worauf jede Variable verweist (daher dynamische Typisierung).

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

In Ihrer Klassendefinition wird nur die spätere beibehalten

Ryan Haining
quelle
0

In Python gibt es keine Vorstellung von Methodenüberladung. Sie können jedoch einen ähnlichen Effekt erzielen, indem Sie optionale Argumente und Schlüsselwortargumente angeben

NLPer
quelle