__getattribute__ est appelé chaque fois qu'un accès d'attribut 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
Cela provoquera une récursion infinie. Le coupable ici est la ligne return self.__dict__[attr]. Imaginons (c'est assez proche de la vérité) que tous les attributs sont stockés self.__dict__et disponibles par leur nom. La ligne
f.a
tente d'accéder à l' aattribut de f. Cela appelle f.__getattribute__('a'). __getattribute__essaie ensuite de charger self.__dict__. __dict__est un attribut des self == fappels python et donc f.__getattribute__('__dict__')qui essaie à nouveau d'accéder à l'attribut '__dict__'. C'est une récursion infinie.
Si __getattr__avait été utilisé à la place,
- Il n'aurait jamais fonctionné car il
fpossède un aattribut.
- S'il s'était exécuté, (disons que vous l'avez demandé
f.b), il n'aurait pas été appelé pour trouver __dict__car il est déjà là et __getattr__n'est invoqué que si toutes les autres méthodes de recherche de l'attribut ont échoué .
La manière «correcte» d'écrire la classe ci-dessus en utilisant __getattribute__est
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)lie la __getattribute__méthode de la superclasse «la plus proche» (officiellement, la classe suivante dans l'ordre de résolution des méthodes de la classe, ou MRO) à l'objet actuel self, puis l'appelle et laisse faire le travail.
Tous ces problèmes sont évités en utilisant __getattr__ce qui permet à Python de faire son travail normal jusqu'à ce qu'un attribut ne soit pas trouvé. À ce stade, Python transmet le contrôle à votre __getattr__méthode et lui permet de trouver quelque chose.
Il convient également de noter que vous pouvez rencontrer une récursion infinie avec __getattr__.
class Foo(object):
def __getattr__(self, attr):
return self.attr
Je vais laisser celui-ci comme un exercice.