In contextlib.py sehe ich, wie die ExitStack-Klasse% aufruft co_de% Methode über das Typobjekt ( __enter__()
) anstelle von direkten Methodenaufrufen auf das angegebene Objekt ( type(cm)
).
Ich frage mich warum oder warum nicht.
z.B.
Zuerst passiert das, wenn Sie with something
machen, es ist nicht nur contextlib
, das nach einer speziellen Methode für den Typ sucht. Es ist auch erwähnenswert, dass dasselbe auch mit anderen speziellen Verfahren geschieht: z.B. a + b
ergibt type(a).__add__(a, b)
.
Aber warum passiert das? Dies ist eine Frage, die oft auf den Mailinglisten python-dev und python-ideas auftaucht. Und wenn ich "oft" sage, meine ich "sehr oft".
Die letzten waren diese: Fehlende Kernfunktion: + - * / | &Ampere; Rufen Sie nicht getattr und Entfernen der speziellen Methodensuche auf .
Hier sind einige interessante Punkte:
Das aktuelle Verhalten ist von Entwurf - spezielle Methoden werden als gesucht Slots in der Klasse des Objekts, nicht als Instanzattribute. Dies erlaubt der Interpreter, um mehrere Schritte in der normalen Instanz zu umgehen Attributsuchprozess.
Es ist erwähnenswert, dass das Verhalten noch magischer ist. Selbst wenn in der Klasse nachgeschlagen wird, implizite spezielle Methode Lookup umgeht
__getattr__
und__getattribute__
der Metaklasse. Also die spezielle Methode Lookup ist nicht nur eine gewöhnliche Suche, die passiert Beginne mit der Klasse anstelle der Instanz; es ist eine völlig magische Suche das greift nicht auf die üblichen Attribut-Zugriff-Anpassung-Haken bei jede Ebene.
Dieses Verhalten ist auch in der Referenzdokumentation dokumentiert: Spezielle Methodensuche , die sagt:
Das Umgehen der
__getattribute__()
-Maschinerie auf diese Weise bietet einen beträchtlichen Spielraum für Geschwindigkeitsoptimierungen innerhalb des Interpreters, auf Kosten einer gewissen Flexibilität bei der Handhabung spezieller Methoden (die spezielle Methode muss auf dem Klassenobjekt selbst gesetzt werden, um es zu sein) konsistent durch den Dolmetscher aufgerufen).
Kurz gesagt, Leistung ist das Hauptanliegen . Aber schauen wir uns das genauer an.
Was ist der Unterschied zwischen type(obj).__enter__()
und obj.__enter__()
?
Wenn Sie obj.attr
schreiben, wird type(obj).__getattribute__('attr')
aufgerufen. Die Standardimplementierung von __getattribute__()
sucht nach attr
im Instanzwörterbuch (d. H.% Co_de%) und in den Klassennamespace. Wenn dies nicht der Fall ist, wird obj.__dict__
.
Nun, das war eine kurze Erklärung, und ich habe einige Details weggelassen, aber es sollte Ihnen eine Vorstellung davon geben, wie kompliziert ein Attribut-Lookup sein kann und wie langsam es werden kann. Das Kurzschließen spezieller Methodensuche liefert sicherlich Leistungsverbesserungen, da das Nachschlagen von type(obj).__getattr__('attr')
auf "klassische" Weise zu langsam sein kann.
Tags und Links python