Ich versuche zu verstehen, wann __getattr__
oder __getattribute__
. Die Erwähnung der Dokumentation__getattribute__
gilt für Klassen neuen Stils. Was sind Klassen neuen Stils?
python
getattr
getattribute
Yarin
quelle
quelle
Antworten:
Ein wesentlicher Unterschied zwischen
__getattr__
und__getattribute__
besteht darin, dass__getattr__
nur aufgerufen wird, wenn das Attribut nicht auf die übliche Weise gefunden wurde. Es ist gut für die Implementierung eines Fallbacks für fehlende Attribute und wahrscheinlich eines von zwei, die Sie möchten.__getattribute__
wird aufgerufen, bevor die tatsächlichen Attribute des Objekts angezeigt werden, und kann daher schwierig zu implementieren sein. Sie können sehr leicht in unendliche Rekursionen geraten.Klassen neuen Stils leiten sich von Klassen
object
alten Stils ab, die in Python 2.x ohne explizite Basisklasse vorliegen. Bei der Wahl zwischen__getattr__
und ist jedoch die Unterscheidung zwischen Klassen im alten und im neuen Stil nicht wichtig__getattribute__
.Sie wollen mit ziemlicher Sicherheit
__getattr__
.quelle
__getattribute__
wird für jeden Zugriff aufgerufen und__getattr__
wird für die Zeiten aufgerufen,__getattribute__
die eine ausgelöst habenAttributeError
. Warum nicht einfach alles in einem behalten?__getattribute__
.objec.__getattribute__
ruftmyclass.__getattr__
unter den richtigen Umständen auf.Sehen wir uns einige einfache Beispiele für beide
__getattr__
und__getattribute__
magische Methoden an.__getattr__
Python ruft die
__getattr__
Methode auf, wenn Sie ein Attribut anfordern, das noch nicht definiert wurde. Im folgenden Beispiel hat meine Klasse Count keine__getattr__
Methode. Wenn ich jetzt versuche, auf beideobj1.mymin
undobj1.mymax
Attribute zuzugreifen, funktioniert alles einwandfrei. Aber wenn ich versuche, auf einobj1.mycurrent
Attribut zuzugreifen , gibt mir PythonAttributeError: 'Count' object has no attribute 'mycurrent'
Nun meine Klasse Count hat
__getattr__
Methode. Wenn ich jetzt versuche, aufobj1.mycurrent
Attribut zuzugreifen , gibt Python mir alles zurück, was ich in meiner__getattr__
Methode implementiert habe . In meinem Beispiel erstellt Python dieses Attribut, wenn ich versuche, ein nicht vorhandenes Attribut aufzurufen, und setzt es auf den ganzzahligen Wert 0.__getattribute__
Nun sehen wir uns die
__getattribute__
Methode an. Wenn Sie eine__getattribute__
Methode in Ihrer Klasse haben, ruft Python diese Methode für jedes Attribut auf, unabhängig davon, ob es vorhanden ist oder nicht. Warum brauchen wir also eine__getattribute__
Methode? Ein guter Grund ist, dass Sie den Zugriff auf Attribute verhindern und sie sicherer machen können, wie im folgenden Beispiel gezeigt.Immer wenn jemand versucht, auf meine Attribute zuzugreifen, die mit der Teilzeichenfolge 'cur' Python beginnen, wird eine
AttributeError
Ausnahme ausgelöst . Andernfalls wird dieses Attribut zurückgegeben.Wichtig: Um eine unendliche Rekursion in der
__getattribute__
Methode zu vermeiden , sollte ihre Implementierung immer die Basisklassenmethode mit demselben Namen aufrufen, um auf alle benötigten Attribute zuzugreifen. Zum Beispiel:object.__getattribute__(self, name)
odersuper().__getattribute__(item)
und nichtself.__dict__[item]
WICHTIG
Wenn Ihre Klasse sowohl die magischen Methoden getattr als auch getattribute enthält ,
__getattribute__
wird sie zuerst aufgerufen. Aber wenn__getattribute__
RaisesAttributeError
Ausnahme dann wird die Ausnahme ignoriert und__getattr__
Methode wird aufgerufen. Siehe folgendes Beispiel:quelle
__getattribute__
aber das ist es sicherlich nicht. Denn gemäß Ihrem Beispiel lösen Sie nur__getattribute__
eineAttributeError
Ausnahme aus, wenn das Attribut im__dict__
Objekt nicht vorhanden ist. Dies ist jedoch nicht unbedingt erforderlich, da dies die Standardimplementierung von ist__getattribute__
und infact__getattr__
genau das ist, was Sie als Fallback-Mechanismus benötigen.current
auf Instanzen definiertCount
(siehe__init__
), die Erhöhung so einfach ,AttributeError
wenn das Attribut ist nicht , ist nicht ganz das, was passiert ist - es aufschiebt__getattr__
für alle Namen ‚cur‘ beginnen, einschließlichcurrent
, aber auchcurious
,curly
...Dies ist nur ein Beispiel, das auf der Erklärung von Ned Batchelder basiert .
__getattr__
Beispiel:Und wenn das gleiche Beispiel mit verwendet wird, erhalten
__getattribute__
Sie >>>RuntimeError: maximum recursion depth exceeded while calling a Python object
quelle
__getattr__()
Implementierungen wird nur eine begrenzte Anzahl gültiger Attributnamen akzeptiert, indemAttributeError
ungültige Attributnamen ausgelöst werden, wodurch subtile und schwer zu debuggende Probleme vermieden werden . In diesem Beispiel werden alle Attributnamen unbedingt als gültig akzeptiert - ein bizarrer (und offen gesagt fehleranfälliger) Missbrauch von__getattr__()
. Wenn Sie wie in diesem Beispiel die vollständige Kontrolle über die Attributerstellung wünschen, möchten Sie__getattribute__()
stattdessen.defaultdict
.__getattr__
es vor der Suche nach Superklassen aufgerufen wird . Dies ist für eine direkte Unterklasse von in Ordnungobject
, da die einzigen Methoden, die Sie wirklich interessieren, magische Methoden sind, die die Instanz ohnehin ignorieren. Bei einer komplexeren Vererbungsstruktur entfernen Sie jedoch vollständig die Möglichkeit, etwas vom übergeordneten Element zu erben.Klassen
object
neuen Stils erben von oder von einer anderen neuen Stilklasse:Old-Style-Klassen nicht:
Dies gilt nur für Python 2 - in Python 3 werden mit allen oben genannten Methoden Klassen neuen Stils erstellt.
Siehe 9. Klassen (Python-Tutorial), NewClassVsClassicClass und Was ist der Unterschied zwischen alten und neuen Stilklassen in Python? für Details.
quelle
Klassen neuen Stils sind solche, die "Objekt" (direkt oder indirekt) unterordnen. Sie haben
__new__
zusätzlich zu__init__
und etwas rationaleres Verhalten auf niedriger Ebene eine Klassenmethode .Normalerweise möchten Sie überschreiben
__getattr__
(wenn Sie dies auch überschreiben), andernfalls fällt es Ihnen schwer, die Syntax "self.foo" in Ihren Methoden zu unterstützen.Zusätzliche Informationen: http://www.devx.com/opensource/Article/31482/0/page/4
quelle
Beim Lesen von Beazley & Jones PCB bin ich auf einen expliziten und praktischen Anwendungsfall gestoßen
__getattr__
, der bei der Beantwortung des "Wann" -Teils der OP-Frage hilft. Von dem Buch:"Die
__getattr__()
Methode ähnelt einem Sammelbegriff für die Attributsuche. Diese Methode wird aufgerufen, wenn Code versucht, auf ein nicht vorhandenes Attribut zuzugreifen." Wir wissen dies aus den obigen Antworten, aber in PCB-Rezept 8.15 wird diese Funktionalität verwendet, um das Delegationsdesignmuster zu implementieren . Wenn Objekt A ein Attribut Objekt B hat, das viele Methoden implementiert, an die Objekt A delegieren möchte, anstatt alle Methoden von Objekt B in Objekt A neu zu definieren, nur um die Methoden von Objekt B aufzurufen, definieren Sie eine__getattr__()
Methode wie folgt:Dabei ist _b der Name des Attributs von Objekt A, das ein Objekt B ist. Wenn eine für Objekt B definierte Methode für Objekt A aufgerufen wird, wird die
__getattr__
Methode am Ende der Suchkette aufgerufen. Dies würde auch den Code sauberer machen, da Sie keine Liste von Methoden definiert haben, die nur zum Delegieren an ein anderes Objekt definiert sind.quelle