__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 aall'attributo di f. Questo chiama f.__getattribute__('a'). __getattribute__quindi tenta di caricare self.__dict__. __dict__è un attributo di self == fe 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é
fha un aattributo.
- 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, selfquindi 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.