__getattribute__
bir öznitelik erişimi gerçekleştiğinde çağrılır.
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
Bu sonsuz tekrarlamaya neden olur. Buradaki suçlu çizgi return self.__dict__[attr]
. Tüm niteliklerin self.__dict__
adlarına göre depolandığını ve mevcut olduklarını varsayalım (gerçeğe yeterince yakın) . Çizgi
f.a
a
özelliğine erişmeye çalışır f
. Bu çağırıyor f.__getattribute__('a')
. __getattribute__
sonra yüklemeye çalışır self.__dict__
. __dict__
bir özniteliktir self == f
ve bu nedenle f.__getattribute__('__dict__')
yine özniteliğe erişmeye çalışan python çağrılarıdır '__dict__
'. Bu sonsuz özyineleme.
Eğer __getattr__
o zaman yerine kullanılmıştır vardı
- Asla koşmazdı çünkü
f
bir a
niteliği var.
- Çalışmış olsaydı, (diyelim ki siz istediniz
f.b
), o zaman __dict__
zaten orada olduğu ve __getattr__
yalnızca özniteliği bulmanın diğer tüm yöntemleri başarısız olduğunda çağrıldığı için bulmak için çağrılmazdı .
Kullanarak yukarıdaki sınıfını yazmaya 'doğru' yolu __getattribute__
olduğunu
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)
__getattribute__
'en yakın' üst sınıf yöntemini (resmi olarak, sınıfın Yöntem Çözüm Sırası veya MRO'daki bir sonraki sınıf) geçerli nesneye bağlar self
ve sonra çağırır ve bunu yapmasına izin verir.
Tüm bu sorun, bir öznitelik bulunana kadar __getattr__
Python'un normal bir şey yapmasına izin veren kullanarak önlenir . Bu noktada, Python __getattr__
yönteminizi kontrol eder ve bir şey bulmasına izin verir.
Ayrıca sonsuz özyineleme ile karşılaşabileceğinizi belirtmek gerekir __getattr__
.
class Foo(object):
def __getattr__(self, attr):
return self.attr
Bunu egzersiz olarak bırakacağım.