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 D
harus 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
super
untuk 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 super
untuk 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