Wie wird die __getattribute__
Methode angewendet?
Es wird vor der normalen gepunkteten Suche aufgerufen. Wenn es erhöht AttributeError
, rufen wir an __getattr__
.
Die Anwendung dieser Methode ist eher selten. In der Standardbibliothek gibt es nur zwei Definitionen:
$ grep -Erl "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py
Beste Übung
Der richtige Weg, um den Zugriff auf ein einzelnes Attribut programmgesteuert zu steuern, ist mit property
. Die Klasse D
sollte wie folgt geschrieben werden (mit dem Setter und Deleter optional, um das offensichtliche beabsichtigte Verhalten zu replizieren):
class D(object):
def __init__(self):
self.test2=21
@property
def test(self):
return 0.
@test.setter
def test(self, value):
'''dummy function to avoid AttributeError on setting property'''
@test.deleter
def test(self):
'''dummy function to avoid AttributeError on deleting property'''
Und Verwendung:
>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
Eine Eigenschaft ist ein Datendeskriptor, daher ist sie das erste, wonach im normalen Algorithmus für die gepunktete Suche gesucht wird.
Optionen für __getattribute__
Sie haben mehrere Möglichkeiten, wenn Sie unbedingt die Suche für jedes Attribut über implementieren müssen __getattribute__
.
- erhöhen
AttributeError
, wodurch __getattr__
aufgerufen wird (falls implementiert)
- gib etwas davon zurück von
- Verwenden Sie
super
, um die übergeordnete object
Implementierung (wahrscheinlich ) aufzurufen
- Berufung
__getattr__
- Implementieren Sie irgendwie Ihren eigenen gepunkteten Suchalgorithmus
Beispielsweise:
class NoisyAttributes(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self, name):
print('getting: ' + name)
try:
return super(NoisyAttributes, self).__getattribute__(name)
except AttributeError:
print('oh no, AttributeError caught and reraising')
raise
def __getattr__(self, name):
"""Called if __getattribute__ raises AttributeError"""
return 'close but no ' + name
>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20
Was du ursprünglich wolltest.
Und dieses Beispiel zeigt, wie Sie das tun können, was Sie ursprünglich wollten:
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else:
return super(D, self).__getattribute__(name)
Und wird sich so verhalten:
>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test
Traceback (most recent call last):
File "<pyshell#216>", line 1, in <module>
del o.test
AttributeError: test
Code-Review
Ihr Code mit Kommentaren. Sie haben eine gepunktete Suche nach sich selbst in __getattribute__
. Aus diesem Grund wird ein Rekursionsfehler angezeigt. Sie können überprüfen, ob der Name lautet, "__dict__"
und ihn super
zur Problemumgehung verwenden, dies gilt jedoch nicht __slots__
. Das überlasse ich dem Leser als Übung.
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else: # v--- Dotted lookup on self in __getattribute__
return self.__dict__[name]
>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp