__getattribute__ wird aufgerufen, wenn ein Attributzugriff erfolgt.
class Foo(object):
def __init__(self, a):
self.a = 1
def __getattribute__(self, attr):
try:
return self.__dict__[attr]
except KeyError:
return 'default'
f = Foo(1)
f.a
Dies führt zu einer unendlichen Rekursion. Der Schuldige hier ist die Linie return self.__dict__[attr]. Stellen wir uns vor (es ist nah genug an der Wahrheit), dass alle Attribute in self.__dict__ihrem Namen gespeichert sind und unter diesem Namen verfügbar sind. Die Linie
f.a
versucht, auf das aAttribut von zuzugreifen f. Dies ruft auf f.__getattribute__('a'). __getattribute__versucht dann zu laden self.__dict__. __dict__ist ein Attribut von self == fund so Python-Aufrufe, f.__getattribute__('__dict__')die erneut versuchen, auf das Attribut zuzugreifen '__dict__'. Dies ist eine unendliche Rekursion.
Wenn __getattr__stattdessen verwendet worden wäre
- Es wäre nie gelaufen, weil
fes ein aAttribut hat.
- Wenn es ausgeführt worden wäre (sagen wir, dass Sie danach gefragt haben
f.b), wäre es nicht zum Suchen aufgerufen worden, __dict__da es bereits vorhanden ist und __getattr__nur aufgerufen wird, wenn alle anderen Methoden zum Suchen des Attributs fehlgeschlagen sind .
Die 'richtige' Art, die obige Klasse mit zu schreiben, __getattribute__ist
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)bindet die __getattribute__Methode der 'nächsten' Oberklasse (formal die nächste Klasse in der Method Resolution Order oder MRO der Klasse) an das aktuelle Objekt selfund ruft sie dann auf und lässt dies die Arbeit erledigen.
All diese Probleme werden vermieden, indem __getattr__Python so lange ausgeführt wird, bis ein Attribut nicht gefunden wird. An diesem Punkt übergibt Python die Kontrolle an Ihre __getattr__Methode und lässt sie sich etwas einfallen lassen.
Es ist auch erwähnenswert, dass Sie mit in eine unendliche Rekursion geraten können __getattr__.
class Foo(object):
def __getattr__(self, attr):
return self.attr
Ich werde das als Übung belassen.