Bagaimana __getattribute__metode ini digunakan?
Ini dipanggil sebelum pencarian titik-titik normal. Jika itu timbul AttributeError, maka kita panggil __getattr__.
Penggunaan metode ini agak jarang. Hanya ada dua definisi di pustaka standar:
$ grep -Erl "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py
Praktek terbaik
Cara yang tepat untuk mengontrol akses secara terprogram ke satu atribut adalah dengan property. Kelas Dharus ditulis sebagai berikut (dengan setter dan deleter secara opsional untuk mereplikasi perilaku yang dimaksudkan):
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'''
Dan penggunaan:
>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
Properti adalah deskriptor data, jadi ini adalah hal pertama yang dicari dalam algoritme pencarian titik-titik normal.
Opsi untuk __getattribute__
Anda memiliki beberapa opsi jika Anda benar-benar perlu mengimplementasikan pencarian untuk setiap atribut melalui __getattribute__.
- meningkatkan
AttributeError, menyebabkan __getattr__dipanggil (jika diterapkan)
- mengembalikan sesuatu darinya
- menggunakan
superuntuk memanggil orang tua (mungkinobject implementasi )
- panggilan
__getattr__
- menerapkan algoritme pencarian titik-titik Anda sendiri
Sebagai contoh:
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
Apa yang awalnya Anda inginkan.
Dan contoh ini menunjukkan bagaimana Anda dapat melakukan apa yang awalnya Anda inginkan:
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)
Dan akan berperilaku seperti ini:
>>> 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
Peninjauan kode
Kode Anda dengan komentar. Anda memiliki pencarian titik-titik pada diri sendiri __getattribute__. Inilah mengapa Anda mendapatkan kesalahan rekursi. Anda dapat memeriksa apakah namanya "__dict__"dan digunakan superuntuk mengatasinya, tetapi itu tidak mencakup __slots__. Saya akan serahkan itu sebagai latihan kepada pembaca.
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