Gibt die Python-Klasse __init__ method implizit None zurück?

7

Ich habe versucht, einen Wert in einem Klassenkonstruktor ( init ) zurückzugeben:

%Vor%

Es gibt jedoch einen Laufzeitfehler, der besagt, dass init None zurückgeben soll. Wenn dies der Fall ist, wie zu verstehen:

%Vor%

wo "a" als die Klasseninstanz zugewiesen wird?

    
Hailiang Zhang 24.10.2012, 05:11
quelle

4 Antworten

27

Genau genommen ist es nicht A.__new__() , das die Instanz a erstellt.

Wenn Sie auch class A(object): (oder class A: definieren, wenn Sie Python3 verwenden, ist class A: das alten Stil Klasse, die veraltet ist ), ist es __new__ von der geerbten object.__new__() , die zum Erstellen der aufgerufen wird Instanz a .

Wenn a = A() ausgeführt wird, geschieht Folgendes:

  1. A() ist eine Abkürzung für A.__call__
  2. object.__new__(cls, *args, **kwargs) wo cls=A , was passiert eigentlich unter Haube, um die Instanz a zu erstellen. Er weist den Speicher für das neue Objekt zu und sollte dann ein neues Objekt (die Instanz) zurückgeben.
  3. wenn und nur wenn das neu erstellte Objekt zurückgegeben wird, wird __init__(self) dann mit dem neu erzeugten Objekt aufgerufen, das an es übergeben wird, um das Objekt "zu initialisieren".

Betrachten Sie die folgende Demo:

  • Wenn wir __new__ überschreiben und kein Objekt mehr zurückgeben, wird __init__ nicht angerufen werden:

    %Vor%
  • Geben Sie jetzt eine neue Instanz mit object.__new__ zurück, und Sie werden das sehen nach __new__ , __init__ würde auch aufgerufen:

    %Vor%

Hier ist eine weitere Demo, um die Unterschiede anzuzeigen. Beachten Sie, dass die Instanz a ohne Aufruf von __init__() :

erstellt werden kann %Vor%

Jetzt für die Neugierigen (und auch um meinen eigenen Speicher zu aktualisieren =]):

Grob gesagt gibt es zwei Möglichkeiten, neue Objekte in Python zu erstellen:

Erstellen Sie ein neues Objekt ( type / class ) durch Unterklassenbildung:

class statements weist Python an, ein neues type / class Objekt zu erstellen (by Unterklasse einer vorhandenen type / Klasse wie object ):

%Vor%

Tatsächlich haben alle Klassen / Typ Objekte den Typ type . Der Typ von type ( type(type) ) ist immer noch Typ.

Sie können ein Objekt type / class ableiten.

Erstellen Sie ein neues Objekt ( instance ), indem Sie Folgendes instanziieren:

Sie können auch ein neues Objekt erstellen, indem Sie ein vorhandenes Objekt type einfügen. Dies geschieht über den Operator __call__ (Kürzel by () ):

%Vor%

Unterklasse eines Instanzobjekts nicht möglich.

(Beachten Sie, dass Sie ein neues -Instanz -Objekt auch auf andere Weise erstellen können, z da er den Listenoperator [1,2,3] verwendet, erstellt er in diesem Fall eine Listeninstanz)

Sie können den Typ eines Objekts anhand von type(my_obj) oder my_object.__class__ überprüfen.

Jetzt wissen Sie, wie ein Instanzobjekt erstellt wird, aber was wirklich das -Typ / Klasse -Objekt erstellt (das das Erstellen von Instanzobjekten ermöglicht) )?

Tatsächlich werden diese Objekte auch durch Instanziierung erzeugt, obwohl es a etwas andere Art von Instanziierung von dem, was zuvor erwähnt wurde.

Neben class statement können Sie auch verwenden type(cls_name, parent_class_tuple, attr_dict) , um eine neue Klasse zu erstellen. Zum Beispiel:

%Vor%

erstellt die Hello -Klasse wie zuvor gezeigt.

Was ist type ? Geben Sie metaclass ein.

type ist eine Metaklasse , die die Klasse der Klasse ist, d. h. Klassen sind Instanzen von Metaklassen. Das __class__ von type ist immer noch type .

Hier ist ein Graph, der die Beziehungen zwischen Metaklasse , Klasse , Instanz :

%Vor%

Wenn die Metaklasse type aufgerufen wird, um eine neue Klasse zu erstellen, geht der ähnliche Ablauf:

  1. type.__call__() wird ausgeführt
  2. type.__new__() weist Speicher zu und gibt dann eine neue Klasse (ein Metaklassen-Objekt) zurück und ruft dann type.__init__() .
  3. auf
  4. type.__init__() initialisiert die neu erstellte Klasse, die von Schritt 2 übergeben wurde.

Sie können sogar eine neue Metaklasse erstellen, indem Sie type :

erstellen %Vor%

Dann können Sie eine neue Klasse aus dieser MyMeta metaclass erstellen, genau wie Sie mit type :

%Vor%

Oder verwenden Sie __metaclass__ bei der Definition Ihrer Klasse, die genau das hat gleicher Effekt wie oben gezeigt:

%Vor%     
K Z 24.10.2012, 05:30
quelle
7

Es funktioniert so:

Sie tun:

%Vor%

A.__new__() wird aufgerufen und gibt eine Instanz der Klasse A zurück.

Äquivalent:

%Vor%

Python ruft dann

auf %Vor%

Welche, wie die Fehlermeldung sagt, sollte keinen Wert zurückgeben.

    
Joel Cornett 24.10.2012 05:15
quelle
4

Wie Sie wissen, ist alles in Python ein Objekt und Klassen sind keine Ausnahme. Die Klasse A ist ein Objekt mit einer Methode __call__(...) , mit der Sie Dinge wie a = A() schreiben können. Unter der Haube erstellt A.__call__ zuerst ein Objekt mit einer statischen Methode __new__ (die eine sinnvolle Standardimplementierung hat) und ruft dann das __init__ des neuen Objekts mit den richtigen Konstruktorargumenten auf.

    
bereal 24.10.2012 05:19
quelle
1

Die Anforderung, dass __init__ None zurückgeben soll, ist eine bewusste Implementierungsauswahl, mit der Sie sich darauf verlassen können, dass das Objekt vom Typ class ein Objekt konsistent zurückgibt vom Typ Instanz der Klasse. Es ist das gleiche in vielen anderen Sprachen wie C ++.

Wenn es anders implementiert wird, würde es nutzlose Verwirrung schaffen.

    
root 24.10.2012 05:27
quelle

Tags und Links