701 Stimmen

Warum wird __init__() immer nach __new__() aufgerufen?

Ich versuche gerade, eine meiner Klassen zu rationalisieren und habe einige Funktionen im gleichen Stil wie die Fliegengewicht-Designmuster .

Allerdings bin ich ein wenig verwirrt, warum __init__ wird immer aufgerufen nach __new__ . Das habe ich nicht erwartet. Kann mir jemand sagen, warum das passiert und wie ich diese Funktion anders implementieren kann? (Abgesehen davon, dass ich die Implementierung in die __new__ was sich ziemlich hakelig anfühlt.)

Hier ist ein Beispiel:

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()

Ausgänge:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

Warum?

1 Stimmen

Versuchte, Design Patterns zu verstehen, und hörte zum ersten Mal von :flyweight Design Patterns.. und sehr guter Link mit Beispielen in fast allen gängigen Sprachen.

5 Stimmen

Ist es nicht ein Singleton?

2voto

Jay Obermark Punkte 29

En __init__ wird aufgerufen nach __new__ so dass, wenn Sie es in einer Unterklasse überschreiben, Ihr hinzugefügter Code immer noch aufgerufen wird.

Wenn Sie versuchen, eine Klasse zu unterklassifizieren, die bereits eine __new__ jemand, der dies nicht weiß, könnte zunächst die __init__ und Weiterleitung des Anrufs an die Unterklasse __init__ . Diese Konvention der Bezeichnung __init__ nach __new__ hilft, dass es wie erwartet funktioniert.

En __init__ muss noch alle Parameter der Oberklasse berücksichtigen __new__ benötigt, aber wenn Sie dies nicht tun, wird in der Regel ein eindeutiger Laufzeitfehler auftreten. Und die __new__ sollte wahrscheinlich ausdrücklich zulassen, dass *args und '**kw', um zu verdeutlichen, dass die Erweiterung in Ordnung ist.

Es ist im Allgemeinen unhöflich, beides zu haben __new__ y __init__ in der gleichen Klasse auf der gleichen Vererbungsebene, wegen des Verhaltens, das der ursprüngliche Poster beschrieben hat.

1voto

ZQ Hu Punkte 101

Der einfache Grund dafür ist, dass die nuevo wird für die Erstellung einer Instanz verwendet, während init wird für die Initialisierung der Instanz verwendet. Vor der Initialisierung sollte die Instanz zunächst erstellt werden. Aus diesem Grund nuevo sollte aufgerufen werden, bevor init .

1voto

Devin Jeanpierre Punkte 87113

Allerdings bin ich ein wenig verwirrt, warum __init__ wird immer aufgerufen nach __new__ .

Dafür gibt es keinen anderen Grund als den, dass es einfach so gemacht wird. __new__ nicht die Aufgabe hat, die Klasse zu initialisieren, sondern eine andere Methode dies tut ( __call__ möglicherweise - ich weiß es nicht genau).

Damit habe ich nicht gerechnet. Kann mir jemand sagen, warum dies geschieht und wie ich diese Funktionalität anders implementieren? (abgesehen davon, dass ich die Implementierung in die __new__ was sich ziemlich hakelig anfühlt).

Sie könnten __init__ nichts tun, wenn sie bereits initialisiert wurde, oder Sie könnten eine neue Metaklasse mit einer neuen __call__ die nur aufruft __init__ auf neue Instanzen, und gibt ansonsten nur __new__(...) .

1voto

Bei der Instanziierung einer Klasse, zuerst, __neu__() wird aufgerufen, um eine die Instanz einer Klasse entonces __init__() wird zur Initialisierung aufgerufen die Instanz .

__neu__() :

Wird aufgerufen, um eine neue Instanz der Klasse cls zu erstellen. ...

Wenn __new__() während der Objektkonstruktion aufgerufen wird und ein Instanz von cls zurückgibt, dann wird die Methode __init__() der neuen Instanz aufgerufen wie __init__(self[, ...]), ...

__init__() :

Wird aufgerufen, nachdem die Instanz erstellt wurde (durch __new__()), ...

Weil __new__() und __init__() bei der Konstruktion von Objekten zusammenarbeiten (__new__(), um es zu erstellen, und __init__(), um es anzupassen), ...

Zum Beispiel, wenn die Instanziierung Teacher Klasse , zuerst, __neu__() wird aufgerufen, um eine die Instanz von Teacher Klasse entonces __init__() wird zur Initialisierung aufgerufen die Instanz wie unten dargestellt:

class Teacher:
    def __init__(self, name):
        self.name = name

class Student:
    def __init__(self, name):
        self.name = name

obj = Teacher("John") # Instantiation

print(obj.name)

Dies ist die Ausgabe:

<class '__main__.Teacher'>
John

Und mit __new__() von die Instanz von Teacher Klasse können wir erstellen die Instanz von Student Klasse wie unten dargestellt:

# ...

obj = Teacher("John")
print(type(obj))
print(obj.name)

obj = obj.__new__(Student) # Creates the instance of "Student" class
print(type(obj))

Jetzt, die Instanz von Student Klasse wird wie unten dargestellt erstellt:

<class '__main__.Teacher'>
<__main__.Teacher object at 0x7f4e3950bf10>
<class '__main__.Student'> # Here

Wenn wir nun versuchen, die den Wert von name variabel von **der Instanz von Student Klasse wie unten dargestellt:

obj = Teacher("John")
print(type(obj))
print(obj.name)

obj = obj.__new__(Student)
print(type(obj))
print(obj.name) # Tries to get the value of "name" variable

Der folgende Fehler tritt auf, weil die Instanz von Student Klasse nicht initialisiert worden ist durch __init__() noch nicht:

AttributeError: Das Objekt 'Student' hat kein Attribut 'name'.

Also, wir initialisieren die Instanz von Student Klasse wie unten dargestellt:

obj = Teacher("John") 
print(type(obj))
print(obj.name)

obj = obj.__new__(Student)
print(type(obj))
obj.__init__("Tom") # Initializes the instance of "Student" class
print(obj.name)

Dann können wir erhalten den Wert von name variabel de die Instanz von Student Klasse wie unten dargestellt:

<class '__main__.Teacher'>
John
<class '__main__.Student'>
Tom # Here

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X