2010-03-05 11 views
2

Le code suivant:Pourquoi le paramètre "name" de __setattr__ inclut-il la classe, mais __getattr__ ne l'est pas?

class MyClass(): 
    def test(self): 
     self.__x = 0 

    def __setattr__(self, name, value): 
     print name 

    def __getattr__(self, name): 
     print name 
     raise AttributeError(name) 

x = MyClass() 
x.test() 
x.__y 

Sorties:

_MyClass__x 
__y 
Traceback (most recent call last): 
... 
AttributeError: __y 

La documentation est tout à fait inutile indiquant le « nom » est le « nom de l'attribut », mais pour une raison quelconque, il est différent selon que vous le définissez ou l'obtenez.

Ce que je veux savoir est:

  • que je fais quelque chose de fondamentalement mal ici?
  • Comment puis-je obtenir x dans le premier cas au lieu de _MyClass__x?

Répondre

4

Le double trait de soulignement appelle le nom mangling. Si vous n'avez pas besoin mangling nom, ne pas utiliser le double undescore

What is the meaning of a single- and a double-underscore before an object name?

De l'Python docs

9,6. Variables privées

Les variables d'instance "privées" auxquelles on ne peut accéder qu'à l'intérieur d'un objet n'existent pas en Python. Cependant, il existe une convention suivie de la plupart des codes Python: un nom précédé d'un trait de soulignement (par exemple _spam) doit être traité comme une partie non publique de l'API (qu'il s'agisse d'une fonction, d'une méthode ou d'un membre de données) . Il devrait être considéré comme un détail de mise en œuvre et sujet à changement sans préavis. Comme il existe un cas d'utilisation valide pour les membres privés de classe (à savoir pour éviter les conflits de noms de noms avec des noms définis par des sous-classes), la prise en charge d'un tel mécanisme est limitée. Tout identificateur de la forme __spam (au moins deux traits de soulignement principaux, au plus un trait de soulignement final) est textuellement remplacé par _classname__spam, où classname est le nom de classe actuel avec le ou les traits de soulignement supprimés. Ce dédoublement est fait sans tenir compte de la position syntaxique de l'identificateur, tant qu'il se produit dans la définition d'une classe. Notez que les règles de mangling sont conçues principalement pour éviter les accidents; il est toujours possible d'accéder ou de modifier une variable considérée comme privée. Cela peut même être utile dans des circonstances spéciales, comme dans le débogueur.

Notez que le code transmis à exec, eval() ou execfile() ne considère pas que le nom de classe de la classe invoquante est la classe en cours; ceci est similaire à l'effet de l'instruction globale, dont l'effet est également limité au code qui est compilé octet ensemble. La même restriction s'applique à getattr(), setattr() et delattr(), ainsi que lors de la référence __dict__ directement.

+0

Oups, j'ai manqué les caractères de soulignement du '__y'. Je l'ai corrigé maintenant.Il y a toujours une asymétrie, mais je pense que vous avez atteint le problème principal. – Draemon

1

Je ne sais pas exactement pourquoi cela se produit, mais si vous utilisez _x plutôt que __x il fonctionne comme on peut s'y attendre.

+0

il est appelé mangling name: http://docs.python.org/tutorial/classes.html#private-variables – SilentGhost

+0

En effet. Ce qui est intéressant, c'est que '__x__' n'a pas de nom brouillé. –

+0

@ar, '__x__' a une autre signification particulière –