J'essaie de comprendre la différence entre __getattr__
et __getattribute__
, cependant, je n'y parviens pas.
La réponse à la question Stack Overflow Différence entre __getattr__
vs__getattribute__
dit:
__getattribute__
est invoqué avant de regarder les attributs réels de l'objet et peut donc être difficile à implémenter correctement. Vous pouvez vous retrouver très facilement dans des récursions infinies.
Je n'ai absolument aucune idée de ce que cela signifie.
Ensuite, il poursuit:
Vous le voulez presque certainement
__getattr__
.
Pourquoi?
J'ai lu qu'en cas d' __getattribute__
échec, __getattr__
est appelé. Alors pourquoi deux méthodes différentes font-elles la même chose? Si mon code implémente les nouvelles classes de style, que dois-je utiliser?
Je cherche quelques exemples de code pour effacer cette question. J'ai googlé au mieux de mes capacités, mais les réponses que j'ai trouvées ne discutent pas le problème à fond.
S'il existe de la documentation, je suis prêt à le lire.
la source
Réponses:
Quelques notions de base en premier.
Avec les objets, vous devez gérer ses attributs. Normalement, nous le faisons
instance.attribute
. Parfois, nous avons besoin de plus de contrôle (lorsque nous ne connaissons pas le nom de l'attribut à l'avance).Par exemple,
instance.attribute
deviendraitgetattr(instance, attribute_name)
. En utilisant ce modèle, nous pouvons obtenir l'attribut en fournissant l' attribut_name sous forme de chaîne.Utilisation de
__getattr__
Vous pouvez également indiquer à une classe comment gérer les attributs qu'elle ne gère pas explicitement et le faire via la
__getattr__
méthode.Python appellera cette méthode chaque fois que vous demanderez un attribut qui n'a pas déjà été défini, vous pouvez donc définir quoi en faire.
Un cas d'utilisation classique:
Mises en garde et utilisation de
__getattribute__
Si vous devez intercepter chaque attribut, qu'il existe ou non , utilisez-le à la
__getattribute__
place. La différence est que__getattr__
seuls les attributs qui n'existent pas sont appelés. Si vous définissez un attribut directement, le référencement de cet attribut le récupérera sans appeler__getattr__
.__getattribute__
est appelé tout le temps.la source
getattr(instance, attribute_name)
.". N'est-ce pas__getattribute__(instance, attribute_name)
?getattr
est une fonction intégrée.getattr(foo, 'bar')
est équivalent àfoo.bar
.__getattr__
n'est appelé que s'il est défini, car il n'est pas hérité deobject
__getattribute__
est appelé chaque fois qu'un accès d'attribut se produit.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ésself.__dict__
et disponibles par leur nom. La lignetente d'accéder à l'
a
attribut def
. Cela appellef.__getattribute__('a')
.__getattribute__
essaie ensuite de chargerself.__dict__
.__dict__
est un attribut desself == f
appels python et doncf.__getattribute__('__dict__')
qui essaie à nouveau d'accéder à l'attribut'__dict__
'. C'est une récursion infinie.Si
__getattr__
avait été utilisé à la place,f
possède una
attribut.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__
estsuper(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 actuelself
, 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__
.Je vais laisser celui-ci comme un exercice.
la source
Je pense que les autres réponses ont fait un excellent travail pour expliquer la différence entre
__getattr__
et__getattribute__
, mais une chose qui n'est peut-être pas claire est la raison pour laquelle vous voudriez l'utiliser__getattribute__
. Ce qui est cool,__getattribute__
c'est qu'il vous permet essentiellement de surcharger le point lors de l'accès à une classe. Cela vous permet de personnaliser la façon dont les attributs sont accessibles à un bas niveau. Par exemple, supposons que je veuille définir une classe où toutes les méthodes qui prennent uniquement un argument self sont traitées comme des propriétés:Et de l'interprète interactif:
Bien sûr, c'est un exemple stupide et vous ne voudrez probablement jamais le faire, mais cela vous montre le pouvoir que vous pouvez obtenir en passant outre
__getattribute__
.la source
J'ai parcouru l'excellente explication des autres. Cependant, j'ai trouvé une réponse simple à partir de ce blog Python Magic Methods and
__getattr__
. Tout ce qui suit vient de là.En utilisant la
__getattr__
méthode magique, nous pouvons intercepter cette recherche d'attributs inexistante et faire quelque chose pour qu'elle n'échoue pas:Mais si l'attribut existe,
__getattr__
ne sera pas invoqué:__getattribute__
est similaire à__getattr__
, avec la différence importante qui__getattribute__
interceptera CHAQUE recherche d'attribut, peu importe si l'attribut existe ou non.Dans cet exemple, l'
d
objet a déjà une valeur d'attribut. Mais lorsque nous essayons d'y accéder, nous n'obtenons pas la valeur attendue d'origine («Python»); nous obtenons tout ce qui__getattribute__
est retourné. Cela signifie que nous avons pratiquement perdu l'attribut value; il est devenu «inaccessible».la source