Ermitteln, ob super () .__ new__ in Python 3 das Objekt .__ new__ sein wird?

8

Nehmen wir an, ich habe eine Klasse, die __new__ aufruft, wie spiele ich gut mit dem mro und rufe nach Bedarf __new__ (mit Argumenten) der Superklassen auf, aber nicht object.__new__ mit zusätzlichen Argumenten? Z.B. Das funktioniert nur, wenn Sie dem Konstruktor keine Argumente übergeben:

%Vor%

Aber das Aufrufen mit Argumenten führt dazu, dass es fehlschlägt (weil Python irgendwann geändert wurde, damit object.__new__ keine Parameter außer der Aufruferklasse akzeptiert):

%Vor%

Wie kann A oder B sagen, dass ihre Superklasse object ist? Sollte ich etwas wie super(A, cls).__new__ is object.__new__ machen? Prüfe das mro()[1] == builtins.object ? Oder muss ich nur entscheiden: "Wollt ihr nie versuchen, super Klassen in __new__ " aufzurufen (z. B. indem ihr return object.__new__(cls) macht)?

EDIT: Wenn die Klasse eine benutzerdefinierte __init__ -Methode definiert, sind Python 2.6 und Python 2.7 in Ordnung, aber es wird immer noch nicht in Python 3 funktionieren.

    
Jeff Tratner 31.10.2013, 23:00
quelle

2 Antworten

6

Wenn wir uns die CPython-Quelle ansehen, sehen wir Folgendes:

  • object.__new__ wird fehlerhaft, wenn mit zusätzlichen Argumenten aufgerufen, und entweder __new__ wird überschrieben oder __init__ ist nicht überschrieben; ebenfalls,
  • object.__init__ wird fehlerhaft, wenn mit zusätzlichen Argumenten aufgerufen wird, und entweder __init__ wird überschrieben oder __new__ ist nicht überschrieben

In 2.x war der Fehler nur ein DeprecationWarning , was Sie möglicherweise beim Experimentieren verpasst haben (beachten Sie, dass seit 2.7 und 3.2 DeprecationWarning wird standardmäßig unterdrückt ).

Die Begründung für dieses Verhalten ist, dass die Typen entweder unveränderlich sind - in diesem Fall sollten sie Argumente in __new__ - oder veränderbar - in diesem Fall sollten sie Argumente in __init__ konsumieren. Dies scheint ein Fall von Praktikabilität zu sein, der die Reinheit übersteigt; Es ist schwierig, an viele produktive Verwendungen von __new__ zu denken, die an den Supertyp delegieren (im Gegensatz zur Protokollierung / Verfolgung), und es wird sehr viel häufiger vorkommen, dass ein super Aufruf an object.__new__ mit zusätzlichen Argumenten ist ein Fehler.

Der sauberste Weg, dies zu handhaben, wird sein, die Identität zu überprüfen: super(A, cls).__new__ is object.__new__ . Begründungen:

  • So entscheidet CPython, ob ein Fehler auftritt (in C statt in Python, aber die Logik ist gleich):

    %Vor%
  • object.__new__ macht nichts mit den Argumenten, außer zu entscheiden, ob ein Fehler ausgegeben werden soll.

ecatmur 01.11.2013, 10:53
quelle
2

Es liegt wirklich an der benutzerdefinierten Methode __new__ , die Argumente, die sie selbst benutzt und benötigt hat, nicht weiterzugeben. Wenn weder C , B noch A Argumente benötigen, ist die Tatsache, dass object.__new__() eine Ausnahme auslöst, völlig korrekt.

Beachten Sie, dass bald , da Sie auch eine benutzerdefinierte __init__ haben , auch object.__new__ die Ausnahme nicht auslöst. Das liegt daran, dass nun die verbleibenden Argumente an übergeben werden können:

%Vor%

Es scheint, dass sich dieses Verhalten in Python 3 geändert hat.

Sie können testen, um zu sehen, welche __new__ -Methode zurückgegeben wird:

%Vor%     
Martijn Pieters 31.10.2013 23:08
quelle

Tags und Links