__getattribute__
viene chiamato ogni volta che si verifica un accesso all'attributo.
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
Ciò causerà una ricorsione infinita. Il colpevole qui è la linea return self.__dict__[attr]
. Facciamo finta (è abbastanza vicino alla verità) che tutti gli attributi sono memorizzati self.__dict__
e disponibili con il loro nome. La linea
f.a
tenta di accedere a
all'attributo di f
. Questo chiama f.__getattribute__('a')
. __getattribute__
quindi tenta di caricare self.__dict__
. __dict__
è un attributo di self == f
e quindi chiama Python f.__getattribute__('__dict__')
che tenta nuovamente di accedere all'attributo '__dict__
'. Questa è una ricorsione infinita.
Se __getattr__
fosse stato usato invece allora
- Non sarebbe mai stato eseguito perché
f
ha un a
attributo.
- Se fosse stato eseguito (supponiamo che tu lo chiedessi
f.b
), non sarebbe stato chiamato per trovare __dict__
perché è già lì e __getattr__
viene invocato solo se tutti gli altri metodi per trovare l'attributo non sono riusciti .
Il modo 'corretto' di scrivere usando la classe sopra __getattribute__
è
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)
associa il __getattribute__
metodo della superclasse "più vicina" (formalmente, la classe successiva nell'ordine di risoluzione del metodo o MRO della classe) all'oggetto corrente, self
quindi lo chiama e consente di eseguire il lavoro.
Tutti questi problemi vengono evitati utilizzando ciò __getattr__
che consente a Python di fare le cose normali fino a quando non viene trovato un attributo. A quel punto, Python passa il controllo del tuo __getattr__
metodo e gli consente di inventare qualcosa.
Vale anche la pena notare che è possibile imbattersi in una ricorsione infinita con __getattr__
.
class Foo(object):
def __getattr__(self, attr):
return self.attr
Lascio quello come esercizio.