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 Dsollte 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 objectImplementierung (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 superzur 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