Warum 'type (x) .__ geben Sie __ (x)' anstelle von 'x .__ geben Sie __ ()' in der Python-Standard-Contextlib ein?

8

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.

  • gibt es bessere Exception-Traces, wenn ein Fehler auftritt?
  • ist es nur spezifisch für den Codierungsstil eines Modulautors?
  • hat es irgendwelche Leistungsvorteile?
  • vermeidet es einige Artefakte / Nebeneffekte mit komplizierten Typhierarchien?
Achimnol 28.12.2015, 09:37
quelle

1 Antwort

12

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.

     

(Quelle)

  

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.

     

(Quelle)

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__ .

aufgerufen

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.

    
Andrea Corbellini 28.12.2015, 09:45
quelle

Tags und Links