Quelqu'un peut-il expliquer la signification exacte d'avoir des traits de soulignement avant le nom d'un objet en Python, et la différence entre les deux?
En outre, ce sens reste-t-il le même que l'objet en question soit une variable, une fonction, une méthode, etc.?
python
oop
naming-conventions
ivanleoncz
la source
la source
Réponses:
Underscore simple
Les noms, dans une classe, avec un trait de soulignement principal sont simplement pour indiquer aux autres programmeurs que l'attribut ou la méthode est destiné à être privé. Cependant, rien de spécial n'est fait avec le nom lui-même.
Pour citer PEP-8 :
Double soulignement (nom Mangling)
Depuis les documents Python :
Et un avertissement de la même page:
Exemple
la source
__
double soulignement en tant que nom de variable? commea, __ = foo()
D'excellentes réponses à ce jour, mais il manque des petits morceaux. Un trait de soulignement premier single est pas exactement juste une convention: si vous utilisez
from foobar import *
, et le modulefoobar
ne définit pas une__all__
liste, les noms importés du module ne comprennent ceux qui ont un trait de soulignement de premier plan. Disons que c'est surtout une convention, car ce cas est un coin assez obscur ;-).La convention de soulignement principal est largement utilisée non seulement pour les noms privés , mais aussi pour ce que C ++ appellerait ceux protégés - par exemple, les noms de méthodes qui sont entièrement destinées à être remplacées par des sous-classes (même celles qui doivent être remplacées depuis dans la classe de base qu'ils
raise NotImplementedError
! -) sont souvent des noms à soulignement simple pour indiquer au code à l' aide d' instances de cette classe (ou sous-classes) que lesdites méthodes ne sont pas censées être appelées directement.Par exemple, pour créer une file d'attente thread-safe avec une discipline de mise en file d'attente différente de FIFO, on importe Queue, sous-classe Queue.Queue et remplace les méthodes comme
_get
et_put
; "code client" n'appelle jamais ces méthodes ("hook"), mais plutôt les méthodes publiques ("organisantes") telles queput
etget
(c'est ce qu'on appelle le modèle de conception de la méthode modèle - voir par exemple ici pour une présentation intéressante basée sur une vidéo d'un entretien sur le sujet, avec l'ajout de synopsis de la transcription).Edit: Les liens vidéo dans la description des discussions sont maintenant rompus. Vous pouvez trouver les deux premières vidéos ici et ici .
la source
_var_name
ou d'utiliservar_name
+ l'exclusion de__all__
?__all__
chaque fois que vous voulez rendre le modulefrom spam import *
convivial (y compris à l'interpréteur interactif). La plupart du temps, la réponse est donc les deux ._
privé . Évidemment, je parle d'analogies, car rien n'est vraiment privé en Python. Lorsque la plongée en sémantique , je dirais que nous pouvons attacher le_
à de Java protégé depuis proctected dans les moyens Java « classes dérivées et / ou dans un même emballage ». Remplacez le package par le module car PEP8 nous dit déjà que ce_
n'est pas seulement une convention lorsque vous parlez d'*
importations et que vous l'avez. Et__
serait certainement équivalent à privé de Java lorsque l'on parle d'identifiants au sein d'une classe.__foo__
: c'est juste une convention, un moyen pour le système Python d'utiliser des noms qui n'entreront pas en conflit avec les noms d'utilisateurs._foo
: c'est juste une convention, un moyen pour le programmeur d'indiquer que la variable est privée (quoi que cela signifie en Python).__foo
: cela a un sens réel: l'interpréteur remplace ce nom par_classname__foo
comme un moyen de s'assurer que le nom ne chevauchera pas avec un nom similaire dans une autre classe.Aucune autre forme de soulignement n'a de sens dans le monde Python.
Il n'y a aucune différence entre classe, variable, global, etc. dans ces conventions.
la source
__foo
et curieux. Comment peut-il chevaucher des noms de méthode similaires avec d'autres classes? Je veux dire que vous devez toujours y accéder commeinstance.__foo()
(s'il n'a pas été renommé par interprète), non?from module import *
n'importe pas d'objets avec préfixe de soulignement. Par conséquent,_foo
c'est plus qu'une simple convention.B
sous - classe la classeA
, et les deux implémententfoo()
,B.foo()
remplace alors le.foo()
hérité deA
. Une instance deB
ne pourra y accéderB.foo()
, sauf viasuper(B).foo()
.__dunder__
noms, les invocations implicites ignorent le dictionnaire d'instances, c'est donc peut-être un peu plus qu'une simple convention de dénomination dans certains cas (voir la section spéciale de recherche de méthode dans le modèle de données).._variable
est semi-privé et destiné uniquement à la convention.__variable
est souvent considéré à tort comme superprivé, alors que sa signification réelle est simplement de nommer un angle pour empêcher un accès accidentel [1].__variable__
est généralement réservé aux méthodes ou variables intégréesVous pouvez toujours accéder aux
.__mangled
variables si vous le souhaitez. Le double souligne simplement les noms de noms, ou renomme la variable en quelque chose commeinstance._className__mangled
Exemple:
t._b est accessible car il n'est masqué que par convention
t .__ a est introuvable car il n'existe plus en raison de la confusion des noms
En accédant
instance._className__variable
au lieu du simple double soulignement, vous pouvez accéder à la valeur cachéela source
Souligné unique au début:
Python n'a pas de véritables méthodes privées. Au lieu de cela, un trait de soulignement au début d'un nom de méthode ou d'attribut signifie que vous ne devez pas accéder à cette méthode, car elle ne fait pas partie de l'API.
(Cet extrait de code a été extrait du code source de django: django / forms / forms.py). Dans ce code,
errors
est une propriété publique, mais la méthode que cette propriété appelle, _get_errors, est "privée", vous ne devez donc pas y accéder.Deux soulignements au début:
Cela provoque beaucoup de confusion. Il ne doit pas être utilisé pour créer une méthode privée. Il doit être utilisé pour éviter que votre méthode soit remplacée par une sous-classe ou accédée accidentellement. Voyons un exemple:
Production:
Créez maintenant une sous-classe B et personnalisez la méthode __test
La sortie sera ....
Comme nous l'avons vu, A.test () n'a pas appelé les méthodes B .__ test (), comme on pourrait s'y attendre. Mais en fait, c'est le comportement correct pour __. Les deux méthodes appelées __test () sont automatiquement renommées (mutilées) en _A__test () et _B__test (), de sorte qu'elles ne remplacent pas accidentellement. Lorsque vous créez une méthode commençant par __, cela signifie que vous ne voulez pas que quiconque puisse la remplacer, et vous avez uniquement l'intention d'y accéder depuis l'intérieur de sa propre classe.
Deux soulignements au début et à la fin:
Quand nous voyons une méthode comme
__this__
, ne l'appelez pas. C'est une méthode que python est censé appeler, pas vous. Nous allons jeter un coup d'oeil:Il y a toujours un opérateur ou une fonction native qui appelle ces méthodes magiques. Parfois, c'est juste un appel de python dans des situations spécifiques. Par exemple,
__init__()
est appelé lorsque l'objet est créé après__new__()
est appelé pour construire l'instance ...Prenons un exemple ...
Pour plus de détails, consultez le guide PEP-8 . Pour plus de méthodes magiques, voir ce PDF .
la source
Parfois, vous avez ce qui semble être un tuple avec un trait de soulignement comme dans
Dans ce cas, ce qui se passe, c'est que _ () est un alias pour une fonction de localisation qui opère sur du texte pour le mettre dans la langue appropriée, etc. en fonction des paramètres régionaux. Par exemple, Sphinx fait cela, et vous trouverez parmi les importations
et dans sphinx.locale, _ () est assigné comme alias d'une fonction de localisation.
la source
Étant donné que tant de gens font référence à la conférence de Raymond , je vais simplement faciliter les choses en écrivant ce qu'il a dit:
Supposons que vous ne conserviez pas une référence locale de
perimeter
inCircle
. Maintenant, une classe dérivéeTire
remplace l'implémentation deperimeter
, sans toucherarea
. Lorsque vous appelezTire(5).area()
, en théorie, il devrait toujours être utiliséCircle.perimeter
pour le calcul, mais en réalité, il utiliseTire.perimeter
, ce qui n'est pas le comportement prévu. C'est pourquoi nous avons besoin d'une référence locale dans Circle.Mais pourquoi
__perimeter
au lieu de_perimeter
? Parce que_perimeter
donne toujours à la classe dérivée la possibilité de remplacer:Les doubles soulignements ont un changement de nom, il y a donc très peu de chances que la référence locale dans la classe parent soit remplacée dans la classe dérivée. ainsi " rend vos sous-classes libres de remplacer n'importe quelle méthode sans casser les autres ".
Si votre classe ne sera pas héritée, ou si la substitution de méthode ne casse rien, alors vous n'avez tout simplement pas besoin
__double_leading_underscore
.la source
Si l'on veut vraiment faire une variable en lecture seule, à mon humble avis la meilleure façon serait d'utiliser la propriété () avec seulement getter passé. Avec property (), nous pouvons avoir un contrôle complet sur les données.
Je comprends que OP a posé une question un peu différente mais comme j'ai trouvé une autre question demandant "comment définir des variables privées" marquées en double avec celle-ci, j'ai pensé ajouter cette information supplémentaire ici.
la source
Accroding à https://dbader.org/blog/meaning-of-underscores-in-python
la source
Excellentes réponses et toutes sont correctes. J'ai fourni un exemple simple avec une définition / signification simple.
Sens:
some_variable --► c'est public, tout le monde peut le voir.
_some_variable --► c'est public tout le monde peut le voir mais c'est une convention pour indiquer privé ... avertissement aucune application n'est effectuée par Python.
__some_varaible --► Python remplace le nom de variable par _classname__some_varaible (AKA name mangling) et il réduit / masque sa visibilité et ressemble plus à une variable privée.
Juste pour être honnête ici selon la documentation Python
L'exemple:
la source
Les traits de soulignement simples sont une convention. il n'y a aucune différence du point de vue de l'interprète si le nom commence ou non par un seul trait de soulignement.
Double avant et arrière underscores sont utilisés pour des méthodes intégrées, telles que
__init__
,__bool__
, etc.Les doubles soulignements principaux sans homologues de fin sont également une convention, cependant, les méthodes de classe seront modifiées par l'interpréteur. Pour les variables ou les noms de fonction de base, aucune différence n'existe.
la source
Votre question est bonne, elle ne concerne pas seulement les méthodes. Les fonctions et les objets dans les modules sont généralement préfixés d'un trait de soulignement et peuvent être préfixés de deux.
Mais les noms __double_underscore ne sont pas modifiés par nom dans les modules, par exemple. Ce qui se passe, c'est que les noms commençant par un (ou plusieurs) traits de soulignement ne sont pas importés si vous importez tous à partir d'un module (à partir de l'importation de module *), ni les noms affichés dans l'aide (module).
la source
Voici un exemple illustratif simple sur la façon dont les propriétés de soulignement double peuvent affecter une classe héritée. Donc, avec la configuration suivante:
si vous créez ensuite une instance enfant dans le python REPL, vous verrez ci-dessous
Cela peut être évident pour certains, mais cela m'a pris au dépourvu dans un environnement beaucoup plus complexe
la source
Les variables d'instance «privées» auxquelles on ne peut accéder que depuis l'intérieur d'un objet n'existent pas en Python. Cependant, il existe une convention qui est suivie par la plupart du code Python: un nom préfixé avec 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 doit être considéré comme un détail d'implémentation et sujet à changement sans préavis.
référence https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
la source
Obtenir les faits de _ et __ est assez facile; les autres réponses les expriment assez bien. L'utilisation est beaucoup plus difficile à déterminer.
Voici comment je le vois:
Doit être utilisé pour indiquer qu'une fonction n'est pas destinée à un usage public comme par exemple une API. Ceci et la restriction d'importation le font se comporter comme
internal
en c #.Doit être utilisé pour éviter la collision de noms dans l'hirarchie d'héritage et pour éviter la liaison tardive. Tout comme privé en c #.
==>
Si vous voulez indiquer que quelque chose n'est pas destiné à un usage public, mais qu'il devrait agir comme un
protected
usage_
. Si vous voulez indiquer que quelque chose n'est pas destiné à un usage public, mais qu'il devrait agir comme unprivate
usage__
.C'est aussi une citation que j'aime beaucoup:
Mais le problème avec cela est à mon avis que s'il n'y a pas d'IDE qui vous avertit lorsque vous substituez des méthodes, la recherche de l'erreur peut vous prendre un certain temps si vous avez accidentellement remplacé une méthode d'une classe de base.
la source