__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' a
attribut de f
. Cela appelle f.__getattribute__('a')
. __getattribute__
essaie ensuite de charger self.__dict__
. __dict__
est un attribut des self == f
appels 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
f
possède un a
attribut.
- 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.