Pourquoi le paramètre « name » à __setattr__ comprennent la classe, mais __getattr__ ne fonctionne pas?
Question
Le code suivant:
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 définissez ou l'obtenir.
Ce que je veux savoir est:
- Suis-je faire quelque chose de fondamentalement mauvais ici?
- Comment puis-je obtenir
x
dans le premier cas au lieu de_MyClass__x
?
La solution
Le double underscore invoque le nom mutiler. Si vous n'avez pas besoin mangling nom, ne pas utiliser le double undescore
Quelle est la signification d'un simple et un double underscore avant un nom d'objet
De Python docs
9,6. Variables privées
exemple « privé » des variables qui ne sont pas accessibles, sauf à l'intérieur d'un objet, n'existent pas en Python. Cependant, il y a une convention qui est suivie par la plupart du code Python: un nom préfixé par un trait de soulignement (par exemple
_spam
) devraient être traités comme une partie non publique de l'API (si elle est une fonction, une méthode ou un membre de données) . Il doit être considéré comme un détail de mise en œuvre et sous réserve de modifications sans préavis.Comme il y a un cas d'utilisation valable pour les membres de la classe-privé (à savoir pour éviter les conflits de noms de noms avec des noms définis par les sous-classes), il y a un soutien limité à un tel mécanisme, appelé nom mutiler. Tout identifiant de la forme
__spam
(au moins deux traits de soulignement, au plus un underscore final) est remplacé par textuellement_classname__spam
, où classname est le nom de la classe actuelle avec underscore (s) dépouillé. Ce mangling se fait sans tenir compte de la position syntaxique de l'identifiant, tant qu'il se produit dans la définition d'une classe.Notez que les règles de la plupart brouillage ont été dessinées pour éviter les accidents; il est toujours possible d'accéder ou de modifier une variable qui est considérée comme privée. Cela peut être utile même dans des circonstances particulières, comme dans le débogueur.
Notez que le code est passé à
exec
,eval()
ouexecfile()
ne considère pas le nom de classe de la classe invocateur être la classe actuelle; ce qui est similaire à l'effet de la déclaration globale, dont l'effet est également limité au code qui est compilé en même temps. La même restriction se rapporte àgetattr()
,setattr()
etdelattr()
, ainsi que lors du référencement directement__dict__
.
Autres conseils
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.