En cas de doute, laissez-le "public" - je veux dire, n'ajoutez rien pour masquer le nom de votre attribut. Si vous avez une classe avec une valeur interne, ne vous inquiétez pas. Au lieu d'écrire:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
écrivez ceci par défaut:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
C'est à coup sûr une manière controversée de faire les choses. Les débutants en Python le détestent et même certains vieux gars de Python méprisent cette valeur par défaut - mais c'est quand même la valeur par défaut, donc je vous recommande vraiment de la suivre, même si vous vous sentez mal à l'aise.
Si vous voulez vraiment envoyer le message "Je ne peux pas y toucher!" pour vos utilisateurs, la méthode habituelle consiste à faire précéder la variable d' un trait de soulignement. Ce n'est qu'une convention, mais les gens la comprennent et font double attention lorsqu'ils traitent de telles choses:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
Cela peut également être utile pour éviter les conflits entre les noms de propriétés et les noms d'attributs:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Qu'en est-il du double trait de soulignement? Eh bien, la magie du double trait de soulignement est principalement utilisée pour éviter la surcharge accidentelle des méthodes et les conflits de noms avec les attributs des superclasses . Cela peut être très utile si vous écrivez une classe qui devrait être étendue plusieurs fois.
Si vous souhaitez l'utiliser à d'autres fins, vous pouvez, mais ce n'est ni habituel ni recommandé.
EDIT : Pourquoi est-ce ainsi? Eh bien, le style Python habituel ne met pas l'accent sur le fait de rendre les choses privées - au contraire! Il y a de nombreuses raisons à cela - la plupart sont controversées ... Voyons quelques-unes d'entre elles.
Python a des propriétés
La plupart des langages OO utilisent aujourd'hui l'approche opposée: ce qui ne doit pas être utilisé ne doit pas être visible, les attributs doivent donc être privés. Théoriquement, cela donnerait des classes plus faciles à gérer et moins couplées, car personne ne changerait imprudemment les valeurs à l'intérieur des objets.
Cependant, ce n'est pas si simple. Par exemple, les classes Java ont de nombreux attributs et getters qui n'obtiennent que les valeurs et les setters qui ne font que définir les valeurs. Vous avez besoin, disons, de sept lignes de code pour déclarer un seul attribut - qui, selon un programmeur Python, est inutilement complexe. De plus, en pratique, vous écrivez simplement tout ce code pour obtenir un champ public, car vous pouvez modifier sa valeur en utilisant les getters et les setters.
Alors, pourquoi suivre cette politique privée par défaut? Rendez simplement vos attributs publics par défaut. Bien sûr, cela pose un problème en Java, car si vous décidez d'ajouter une validation à votre attribut, il vous faudrait tout changer
person.age = age;
dans votre code pour, disons,
person.setAge(age);
setAge()
étant:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
Donc en Java (et dans d'autres langages), la valeur par défaut est d'utiliser les getters et les setters de toute façon, car ils peuvent être ennuyeux à écrire mais peuvent vous faire gagner beaucoup de temps si vous vous trouvez dans la situation que j'ai décrite.
Cependant, vous n'avez pas besoin de le faire en Python, car Python a des propriétés. Si vous avez ce cours:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
et puis vous décidez de valider les âges, vous n'avez pas besoin de changer les person.age = age
morceaux de votre code. Ajoutez simplement une propriété (comme indiqué ci-dessous)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Si vous pouvez le faire et continuer à l'utiliser person.age = age
, pourquoi ajouteriez-vous des champs privés, des getters et des setters?
(En outre, voir Python n'est pas Java et cet article sur les inconvénients liés à l'utilisation des getters et des setters .).
Tout est visible de toute façon - et essayer de se cacher complique simplement votre travail
Même dans les langues où il existe des attributs privés, vous pouvez y accéder via une sorte de bibliothèque de réflexion / introspection. Et les gens le font beaucoup, dans des cadres et pour résoudre des besoins urgents. Le problème est que les bibliothèques d'introspection ne sont qu'un moyen difficile de faire ce que vous pourriez faire avec les attributs publics.
Puisque Python est un langage très dynamique, il est tout simplement contre-productif d'ajouter ce fardeau à vos classes.
Le problème n'est pas possible de voir - il est nécessaire de voir
Pour un Pythonista, l'encapsulation n'est pas l'incapacité de voir les internes des classes, mais la possibilité d'éviter de la regarder. Ce que je veux dire, c'est que l'encapsulation est la propriété d'un composant qui lui permet d'être utilisé sans que l'utilisateur se soucie des détails internes. Si vous pouvez utiliser un composant sans vous soucier de son implémentation, alors il est encapsulé (de l'avis d'un programmeur Python).
Maintenant, si vous avez écrit votre classe de telle manière que vous pouvez l'utiliser sans avoir à penser aux détails d'implémentation, il n'y a aucun problème si vous voulez regarder à l'intérieur de la classe pour une raison quelconque. Le fait est que votre API doit être bonne et le reste, ce sont les détails.
Guido l'a dit
Eh bien, ce n'est pas controversé: il l'a dit, en fait . (Cherchez «kimono ouvert».)
C'est la culture
Oui, il y a quelques raisons, mais aucune raison critique. Il s'agit principalement d'un aspect culturel de la programmation en Python. Franchement, cela pourrait aussi être l'inverse - mais ce n'est pas le cas. De plus, vous pourriez tout aussi facilement demander l'inverse: pourquoi certaines langues utilisent-elles des attributs privés par défaut? Pour la même raison principale que pour la pratique Python: parce que c'est la culture de ces langages, et chaque choix a des avantages et des inconvénients.
Puisqu'il existe déjà cette culture, il est conseillé de la suivre. Sinon, vous serez ennuyé par les programmeurs Python vous disant de supprimer le __
de votre code lorsque vous posez une question dans Stack Overflow :)
Premièrement - Qu'est-ce que la mutilation des noms?
Le changement de nom est appelé lorsque vous êtes dans une définition de classe et que vous utilisez
__any_name
ou__any_name_
, c'est-à-dire deux (ou plus) traits de soulignement de début et au plus un trait de soulignement de fin.Et maintenant:
L'utilisation apparente est d'empêcher les sous-classeurs d'utiliser un attribut que la classe utilise.
Une valeur potentielle consiste à éviter les collisions de noms avec les sous-classes qui souhaitent remplacer le comportement, afin que la fonctionnalité de classe parent continue de fonctionner comme prévu. Cependant, l' exemple de la documentation Python n'est pas substituable à Liskov, et aucun exemple ne me vient à l'esprit où j'ai trouvé cela utile.
Les inconvénients sont que cela augmente la charge cognitive pour la lecture et la compréhension d'une base de code, et en particulier lors du débogage où vous voyez le double nom de soulignement dans la source et un nom mutilé dans le débogueur.
Mon approche personnelle est de l'éviter intentionnellement. Je travaille sur une très grande base de code. Les rares utilisations de celui-ci ressortent comme un pouce endolori et ne semblent pas justifiées.
Vous devez en être conscient afin de le savoir quand vous le voyez.
PEP 8
PEP 8 , le guide de style de la bibliothèque standard Python, dit actuellement (abrégé):
Comment ça marche?
Si vous ajoutez deux traits de soulignement (sans terminer les doubles traits de soulignement) dans une définition de classe, le nom sera mutilé et un trait de soulignement suivi du nom de la classe sera ajouté au début de l'objet:
Notez que les noms ne seront mutilés que lorsque la définition de classe est analysée:
De plus, les nouveaux utilisateurs de Python ont parfois du mal à comprendre ce qui se passe lorsqu'ils ne peuvent pas accéder manuellement à un nom qu'ils voient défini dans une définition de classe. Ce n'est pas une bonne raison contre cela, mais c'est quelque chose à considérer si vous avez un public apprenant.
Un soulignement?
Lorsque mon intention est que les utilisateurs gardent la main sur un attribut, j'ai tendance à n'utiliser qu'un seul trait de soulignement, mais c'est parce que dans mon modèle mental, les sous-classeurs auraient accès au nom (qu'ils ont toujours, car ils peuvent facilement repérer le nom mutilé de toute façon).
Si je
__
passais en revue le code qui utilise le préfixe, je demanderais pourquoi ils invoquent le changement de nom, et s'ils ne pourraient pas faire aussi bien avec un seul trait de soulignement, en gardant à l'esprit que si les sous-classes choisissent les mêmes noms pour la classe et attribut de classe il y aura une collision de nom malgré cela.la source
Je ne dirais pas que la pratique produit un meilleur code. Les modificateurs de visibilité ne font que vous distraire de la tâche à accomplir et, en tant qu'effet secondaire, forcent votre interface à être utilisée comme vous le souhaitez. De manière générale, l'application de la visibilité empêche les programmeurs de gâcher les choses s'ils n'ont pas lu correctement la documentation.
Une bien meilleure solution est la route que Python encourage: vos classes et variables doivent être bien documentées et leur comportement clair. La source doit être disponible. C'est un moyen beaucoup plus extensible et fiable d'écrire du code.
Ma stratégie en Python est la suivante:
Surtout, ce que tout fait doit être clair. Documentez-le si quelqu'un d'autre l'utilise. Documentez-le si vous voulez qu'il soit utile dans un an.
En remarque, vous devriez en fait utiliser protected dans ces autres langues: vous ne savez jamais que votre classe pourrait être héritée plus tard et pour ce qu'elle pourrait être utilisée. Il est préférable de ne protéger que les variables dont vous êtes certain qu'elles ne peuvent ou ne doivent pas être utilisées par du code étranger.
la source
Vous ne devriez pas commencer avec des données privées et les rendre publiques si nécessaire. Au contraire, vous devriez commencer par déterminer l'interface de votre objet. C'est-à-dire que vous devriez commencer par déterminer ce que le monde voit (les trucs publics) et ensuite déterminer quels trucs privés sont nécessaires pour que cela se produise.
D'autres termes rendent difficile de rendre privé ce qui était autrefois public. Ie je vais casser beaucoup de code si je rend ma variable privée ou protégée. Mais avec les propriétés en python, ce n'est pas le cas. Au contraire, je peux conserver la même interface même en réorganisant les données internes.
La différence entre _ et __ est que python tente en fait d'appliquer ce dernier. Bien sûr, cela n'essaie pas vraiment mais cela rend les choses difficiles. Avoir _ dit simplement aux autres programmeurs quelle est l'intention, ils sont libres de l'ignorer à leurs risques et périls. Mais ignorer cette règle est parfois utile. Les exemples incluent le débogage, les hacks temporaires et l'utilisation de code tiers qui n'était pas destiné à être utilisé comme vous l'utilisez.
la source
Il y a déjà beaucoup de bonnes réponses à cela, mais je vais en proposer une autre. C'est aussi en partie une réponse aux gens qui n'arrêtent pas de dire que le double soulignement n'est pas privé (c'est vraiment le cas).
Si vous regardez Java / C #, les deux ont private / protected / public. Tous ces éléments sont des constructions au moment de la compilation . Ils ne sont appliqués qu'au moment de la compilation. Si vous utilisiez la réflexion en Java / C #, vous pourriez facilement accéder à la méthode privée.
Désormais, chaque fois que vous appelez une fonction en Python, vous utilisez intrinsèquement la réflexion. Ces morceaux de code sont les mêmes en Python.
La syntaxe "dot" n'est que du sucre syntaxique pour ce dernier morceau de code. Surtout parce que l'utilisation de getattr est déjà moche avec un seul appel de fonction. Cela empire à partir de là.
Donc, avec cela, il ne peut pas y avoir de version Java / C # de private, car Python ne compile pas le code. Java et C # ne peuvent pas vérifier si une fonction est privée ou publique au moment de l'exécution, car ces informations ont disparu (et il ne sait pas d'où la fonction est appelée).
Maintenant, avec cette information, le nom de la déformation du double trait de soulignement est le plus logique pour atteindre le "caractère privé". Maintenant, lorsqu'une fonction est appelée à partir de l'instance 'self' et qu'elle remarque qu'elle commence par '__', elle exécute simplement le changement de nom juste là. C'est juste plus de sucre syntaxique. Ce sucre syntaxique permet l'équivalent de «privé» dans un langage qui n'utilise que la réflexion pour l'accès aux données membres.
Avertissement: je n'ai jamais entendu personne du développement Python dire quelque chose de tel. La vraie raison du manque de «privé» est culturelle, mais vous remarquerez également que la plupart des langages de script / interprétés n'ont pas de privé. Un privé strictement exécutoire n'est pratique à rien, sauf au moment de la compilation.
la source
Premièrement: pourquoi souhaitez-vous masquer vos données? Pourquoi est-ce si important?
La plupart du temps, vous ne voulez pas vraiment le faire, mais vous le faites parce que les autres le font.
Si vous ne voulez vraiment vraiment pas que les gens utilisent quelque chose, ajoutez un trait de soulignement devant. Voilà ... Les pythonistes savent que les choses avec un seul trait de soulignement ne sont pas garanties de fonctionner à chaque fois et peuvent changer sans que vous le sachiez.
C'est comme ça que nous vivons et cela nous convient.
L'utilisation de deux traits de soulignement rendra votre classe si mauvaise en sous-classe que même vous ne voudrez pas travailler de cette façon.
la source
La réponse choisie explique bien comment les propriétés suppriment le besoin d' attributs privés , mais j'ajouterais également que les fonctions au niveau du module suppriment le besoin de méthodes privées .
Si vous transformez une méthode en fonction au niveau du module, vous supprimez la possibilité pour les sous-classes de la remplacer. Déplacer certaines fonctionnalités au niveau du module est plus pythonique que d'essayer de masquer des méthodes avec une modification des noms.
la source
L'extrait de code suivant expliquera tous les différents cas:
pas de trait de soulignement (a)
impression de tous les attributs valides de l'objet de test
Ici, vous pouvez voir que le nom de __a a été changé en _Test__a pour éviter que cette variable ne soit remplacée par l'une des sous-classes. Ce concept est connu sous le nom de "Name Mangling" en python. Vous pouvez accéder à ceci comme ceci:
De même, dans le cas de _a, la variable sert simplement à informer le développeur qu'elle doit être utilisée comme variable interne de cette classe, l'interpréteur python ne fera rien même si vous y accédez, mais ce n'est pas une bonne pratique.
une variable peut être accessible de n'importe où, c'est comme une variable de classe publique.
J'espère que la réponse vous a aidé :)
la source
À première vue, cela devrait être le même que pour les autres langages (sous «autre», je veux dire Java ou C ++), mais ce n'est pas le cas.
En Java, vous avez rendu privées toutes les variables qui ne devraient pas être accessibles à l'extérieur. En même temps, en Python, vous ne pouvez pas y parvenir car il n'y a pas de "caractère privé" (comme le dit l'un des principes de Python - "Nous sommes tous des adultes"). Donc, le double soulignement signifie seulement "Les gars, n'utilisez pas ce champ directement". La même signification a un trait de soulignement unique, qui dans le même temps ne cause aucun mal de tête lorsque vous devez hériter d'une classe considérée (juste un exemple de problème possible causé par un double tiret bas).
Donc, je vous recommande d'utiliser un seul trait de soulignement par défaut pour les membres "privés".
la source
"En cas de doute sur la question de savoir si une variable doit être privée ou protégée, il vaut mieux choisir private." - oui, c'est la même chose en Python.
Certaines réponses ici parlent de «conventions», mais ne donnent pas les liens vers ces conventions. Le guide faisant autorité pour Python, PEP 8 déclare explicitement:
La distinction entre public et privé, et la transformation des noms en Python ont été prises en compte dans d'autres réponses. Du même lien,
la source
#EXEMPLE DE PROGRAMME POUR LA MANGULATION DE NOM PYTHON
la source