__getattribute__
est appelé à chaque fois qu'un attribut d'accès se produit.
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
Ce sera la cause d'une récursion infinie. Le coupable est ici la ligne return self.__dict__[attr]
. Imaginons (C'est assez proche de la vérité) que tous les attributs sont stockés dans self.__dict__
et disponible par leur nom. La ligne
f.a
les tentatives d'accès à l' a
attribut de l' f
. Cela exige f.__getattribute__('a')
. __getattribute__
puis essaie de charger self.__dict__
. __dict__
est un attribut de l' self == f
et ainsi de python appels f.__getattribute__('__dict__')
qui tente à nouveau d'accéder à l'attribut '__dict__
'. C'est une récursion infinie.
Si __getattr__
a été utilisé à la place alors
- Elle n'aurait jamais exécuté, car
f
a a
d'attribut.
- Si elle avait couru, (disons que vous avez demandé l'
f.b
), alors elle n'aurait pas été appelé à trouver __dict__
parce que c'est déjà là et l' __getattr__
n'est invoquée que si toutes les autres méthodes de trouver l'attribut ont échoué.
La "bonne" façon d'écrire la classe ci-dessus à l'aide de __getattribute__
est
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)
lie l' __getattribute__
méthode du "plus proche" de la superclasse (officiellement, la prochaine classe dans la classe de la Méthode de Résolution de l'Ordre, ou MRO) à l'objet courant en self
, puis l'appelle et permet que de faire le travail.
L'ensemble de ce problème est évité en utilisant __getattr__
qui permet de Python ne c'est chose tout à fait normale jusqu'à ce qu'un attribut n'est pas trouvé. À ce point, Python mains le contrôle de votre __getattr__
méthode et permet de venir avec quelque chose.
Il est également intéressant de noter que vous pouvez exécuter dans une récursion infinie avec __getattr__
.
class Foo(object):
def __getattr__(self, attr):
return self.attr
Je vais laisser ça comme un exercice.