webentwicklung-frage-antwort-db.com.de

Warum haben Eigenschaften in Python Vorrang vor Instanzattributen?

Dieser Artikel beschreibt, wie Python bei der Ausführung von o.a ein Attribut eines Objekts nachschlägt. Die Prioritätsreihenfolge ist interessant - es sucht nach:

  1. Ein Klassenattribut, das ein Datenbeschreiber ist (am häufigsten eine Eigenschaft)
  2. Ein Instanzattribut
  3. Alle anderen Klassenattribute

Wir können dies mit dem folgenden Code bestätigen, der ein Objekt o mit einem Instanzattribut a erstellt, dessen Klasse eine gleichnamige Eigenschaft enthält:

class C:
    def __init__(self):
        self.__dict__['a'] = 1

    @property
    def a(self):
        return 2

o = C()
print(o.a)  # Prints 2

Warum verwendet Python diese Prioritätsreihenfolge anstelle der "naiven" Reihenfolge (Instanzattribute haben Vorrang vor allen Klassenattributen)? Die Prioritätsreihenfolge von Python hat einen erheblichen Nachteil: Die Suche nach Attributen wird langsamer, da Python nicht nur ein Attribut von o zurückgibt (ein häufiger Fall), sondern zuerst die Klasse und alle ihre Superklassenvon o nach einer Datenbeschreiber.

Was ist der Vorteil von Pythons Prioritätsreihenfolge? Dies ist vermutlich nicht nur für die obige Situation der Fall, da eine Instanzvariable und eine gleichnamige Eigenschaft ein echter Fall ist (beachten Sie die Notwendigkeit, self.__dict__['a'] = 1 zum Erstellen des Instanzattributs zu verwenden, da der übliche self.a = 1 die Eigenschaft aufrufen würde).

Gibt es eine andere Situation, in der die "naive" Suchreihenfolge ein Problem verursachen würde?

8
user200783

Guido van Rossum (der ehemalige BDFL von Python) hat dieses Feature entworfen, als 2001 mit Python 2.2 neue Klassen eingeführt wurden. Die Begründung wird in PEP 252 diskutiert. Die Auswirkungen auf die Attributsuche werden explizit erwähnt:

Dieses Schema hat einen Nachteil: In dem, von dem ich annehme, dass es sich am häufigsten um eine Instanzvariable handelt, die im Instanzdict gespeichert ist, werden zwei Verzeichnisse gesucht, während das klassische Schema einen schnellen Test auf Attribute durchführt, der mit zwei Unterstrichen plus einem einzigen Zeichen beginnt Wörterbuchsuche.

Und:

Ein Benchmark bestätigt, dass dies tatsächlich so schnell ist wie bei der Suche nach klassischen Instanzvariablen. Ich mache mir also keine Sorgen mehr.

4
fpbhb

Für alte Klassen ( PEP 252 ):

Das Instanzdikt überschreibt das Klassendiktat mit Ausnahme der speziellen Attribute (wie __dict__ und __class__), die Vorrang vor dem Instanzdikt haben.

Das Überschreiben von __dict__ oder __class__ innerhalb des Instanzdikts würde die Suche nach Attributen beeinträchtigen und dazu führen, dass sich die Instanz auf äußerst seltsame Weise verhält.

In Klassen im neuen Stil wählte Guido die folgende Implementierung der Attributsuche, um die Konsistenz zu gewährleisten ( PEP 252 ):

  1. Schauen Sie in das Typendiktat. Wenn Sie einen Datenbeschreiber finden, verwenden Sie die get()-Methode, um das Ergebnis zu erzeugen. Dies berücksichtigt spezielle Attribute wie __dict__ und __class__.
  2. Schauen Sie in das Instanzdikt. Wenn Sie etwas finden, ist es das. (Dadurch wird die Anforderung berücksichtigt, dass das Instanzdikt normalerweise das Klassendiktat überschreibt.)
  3. Schauen Sie sich das Typ-Dikt erneut an (in Wirklichkeit wird natürlich das gespeicherte Ergebnis aus Schritt 1 verwendet). Wenn Sie einen Deskriptor finden, verwenden Sie die Methode get (). Wenn Sie etwas anderes finden, ist es das; Wenn nicht, erhöhen Sie AttributeError.

Zusammenfassend werden die __dict__- und __class__-Attribute als Eigenschaften (Datendeskriptoren) implementiert. Um einen gültigen Status beizubehalten, kann der Instanzdikt __dict__ und __class__ nicht überschreiben. Daher haben Eigenschaften (Datendeskriptoren) Vorrang vor Instanzattributen.

2
Joshua

Was ich wissen möchte, ist, warum Datendeskriptoren Vorrang vor .__ haben. Instanzattribute?

Wenn es keine Methode gibt, die Vorrang vor der normalen Instanzsuche hat, wie erwarten Sie, dass Instanzattributenzugriffe abgefangen werden? Diese Methoden können keine Instanzattribute selbst sein, da dies ihren Zweck zunichte machen würde (zumindest ohne zusätzliche Konventionen darüber, denke ich).

Abgesehen von dem kurzen Kommentar von @timgeb kann ich nichts besser über Deskriptoren erklären als das offizielle Descriptor How To

1
progmatico