Wie funktioniert super (), indem die Zelle __class__ manuell gefüllt wird?

8

In Python 3 kann man super() anstelle von super(MyClass, self) verwenden, aber das funktioniert nur in Methoden, die innerhalb der Klasse definiert wurden. Wie in Artikel von Michele Simionato beschrieben, funktioniert das folgende Beispiel nicht:

%Vor%

Dies schlägt fehl, weil super() nach einer __class__ Zelle sucht, die nicht in definiert ist dieser Fall.

Ist es möglich, diese Zelle manuell zu setzen, nachdem die Funktion definiert wurde, oder ist das unmöglich?

Leider verstehe ich nicht, wie Zellen in diesem Zusammenhang funktionieren (fand dafür nicht viel Dokumentation). Ich hoffe auf etwas wie

%Vor%

Natürlich würde ich das nur in einer Situation verwenden, in der die Klassenzuweisung eindeutig / eindeutig ist (der gesamte Prozess des Hinzufügens von Methoden zu einer Klasse wird in meinem Fall automatisiert, so dass es einfach wäre, eine solche Zeile hinzuzufügen).

    
nikow 03.02.2011, 10:45
quelle

3 Antworten

15
Ernsthaft: Sie wollen das wirklich nicht tun.

Aber es ist nützlich für fortgeschrittene Benutzer von Python, das zu verstehen, also werde ich es erklären.

Zellen und Freizeichen sind die Werte, die beim Erstellen eines Abschlusses zugewiesen werden. Zum Beispiel

%Vor%

f gibt eine Schließung basierend auf func zurück und speichert einen Verweis auf a . Diese Referenz wird in einer Zelle gespeichert (eigentlich in einer Freevar, aber welche ist die Implementierung). Sie können dies prüfen:

%Vor%

("cells" und "freevars" sind sehr ähnlich. Freevars haben Namen, wo Zellen Indizes haben. Beide sind in func.__closure__ gespeichert, wobei Zellen zuerst kommen. Wir interessieren uns hier nur für freevars , denn das ist Was __class__ ist.)

Sobald Sie das verstanden haben, können Sie sehen, wie super () tatsächlich funktioniert. Jede Funktion, die einen Aufruf von super enthält, ist ein Closure mit einem Freizeichen namens __class__ (das auch hinzugefügt wird, wenn Sie sich selbst auf __class__ beziehen):

%Vor%

(Achtung: Hier werden die Dinge böse.)

Diese Zellen sind in func.__closure__ sichtbar, aber sie sind schreibgeschützt. Du kannst es nicht ändern. Die einzige Möglichkeit, dies zu ändern, besteht darin, eine neue Funktion zu erstellen, die mit dem Konstruktor types.FunctionType ausgeführt wird. Ihre __init__ -Funktion hat jedoch kein __class__ freevar - also müssen wir eins hinzufügen. Das bedeutet, dass wir auch ein neues Code-Objekt erstellen müssen.

Der folgende Code macht das. Ich habe eine Basisklasse B zu Demonstrationszwecken hinzugefügt. Dieser Code macht einige Annahmen, z. Das __init__ hat noch keine freie Variable namens __class__ .

Hier gibt es einen weiteren Hack: Es scheint keinen Konstruktor für den Zelltyp zu geben. Um dies zu umgehen, wird eine Dummy-Funktion C.dummy erzeugt, die die von uns benötigte Zellenvariable hat.

%Vor%     
Glenn Maynard 03.02.2011, 12:09
quelle
2

Sie können das Wörterbuch der Funktion verwenden.

%Vor%

Sie können sogar ein weiteres Attribut member_name hinzufügen, wenn Sie den Namen des Mitglieds in der Funktion nicht fest codieren wollen.

    
Rosh Oxymoron 03.02.2011 11:56
quelle
1

Vielleicht, aber von dir? In beiden Fällen müssen Sie explizit angeben, um welche Klasse es sich handelt, weil der implizite Weg nicht funktioniert hat. Vielleicht kannst du die Zelle explizit irgendwie setzen, aber dafür gibt es keinen Grund. Übergeben Sie die Parameter einfach explizit.

%Vor%

(Es ist besser, wenn Sie die eigentliche Klasse direkt übergeben können, so:

%Vor%

Aber wenn du das kannst, könntest du __init__ direkt auf C setzen, also nimm an, dass du das nicht kannst.

    
Lennart Regebro 03.02.2011 11:16
quelle