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:
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):
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.
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.
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:
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:
Tags und Links python python-3.x super