1500 votes

Quelle est la signification du simple et du double soulignement devant un nom d'objet ?

Quelqu'un peut-il expliquer la signification exacte de l'utilisation d'un simple ou d'un double trait de soulignement devant le nom d'un objet en Python, et la différence entre les deux ?

En outre, cette signification reste-t-elle la même, que l'objet en question soit une variable, une fonction, une méthode, etc.

3 votes

Une excellente réponse courte provenant d'un autre fil de discussion : stackoverflow.com/a/8689983/911945

0 votes

Voir aussi excellent qui traite de la différence entre le soulignement simple et le soulignement double, et qui démontre la "confusion des noms" : Réponse à "Private members in Python" (en anglais)

1334voto

Andrew Keeton Points 6268

Single Underscore

Les noms, dans une classe, avec un trait de soulignement en tête servent simplement à 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.

Je cite PEP-8 :

_single_leading_underscore : indicateur faible "d'usage interne". Par exemple from M import * n'importe pas les objets dont le nom commence par un trait de soulignement.

Double Underscore (confusion de noms)

Desde la documentation Python :

Tout identifiant de la forme __spam (au moins deux traits de soulignement en tête, au plus un trait de soulignement en queue) est remplacé textuellement par _classname__spam , donde classname est le nom de la classe actuelle, sans le(s) trait(s) de soulignement en tête. Ce traitement est effectué sans tenir compte de la position syntaxique de l'identifiant, il peut donc être utilisé pour définir des variables d'instance et de classe class-private, des méthodes, des variables stockées dans des globales, et même des variables stockées dans des instances. private à cette classe sur des instances d'autres classes.

Et un avertissement de la même page :

La gestion des noms est destinée à donner aux classes un moyen facile de définir des variables d'instance et des méthodes "privées", sans avoir à se soucier des variables d'instance définies par des classes dérivées, ou de l'utilisation des variables d'instance par du code extérieur à la classe. Notez que les règles de mangement sont conçues principalement pour éviter les accidents ; il est toujours possible pour une âme déterminée d'accéder ou de modifier une variable qui est considérée comme privée.

Exemple

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

23 votes

Et s'il y a un nom de variable déclaré avec deux caractères de soulignement qui n'est pas dans la classe ? C'est juste une variable normale alors, non ?

0 votes

Excellent ! J'ai appris l'existence des attributs en lecture seule il y a quelques heures à peine et j'étais cette âme déterminée qui essayait de voir si l'un d'eux pouvait être modifié (principalement par des références mémoire). Bien que je sois déçu de découvrir que c'est aussi simple que mc.__dict__['_MyClass__superprivate'] = 'Die' mais je ne m'attends pas à ce que l'utilisateur moyen le sache.

5 votes

Quelle est la signification de simplement __ double underscore comme nom de variable ? comme a, __ = foo()

361voto

Ned Batchelder Points 128913

__foo__ Il s'agit simplement d'une convention, un moyen pour le système Python d'utiliser des noms qui n'entrent pas en conflit avec les noms d'utilisateur.

_foo Il s'agit juste d'une convention, une façon pour le programmeur d'indiquer que la variable est privée (quoi que cela signifie en Python).

__foo : cela a une signification réelle : l'interpréteur remplace ce nom par _classname__foo afin de s'assurer que le nom ne se superpose pas à un nom similaire dans une autre classe.

Aucune autre forme d'underscores n'a de sens dans le monde Python.

Il n'y a aucune différence entre classe, variable, global, etc. dans ces conventions.

7 votes

Je viens de tomber sur __foo et curieux. Comment peut-il se superposer à des noms de méthodes similaires dans d'autres classes ? Je veux dire que vous devez toujours y accéder comme instance.__foo() (s'il n'a pas été renommé par l'interpréteur), n'est-ce pas ?

110 votes

Ce type déclare que from module import * n'importe pas les objets préfixés par un trait de soulignement. Par conséquent, _foo est plus qu'une simple convention.

5 votes

@Bibhas : si la classe B Sous-classes de la classe A et les deux mettent en œuvre foo() entonces B.foo() remplace le .foo() hérité de A . Une instance de B ne pourront accéder qu'à B.foo() sauf via super(B).foo() .

347voto

Alex Martelli Points 330805

D'excellentes réponses jusqu'à présent, mais il manque quelques éléments. Un simple trait de soulignement en tête n'est pas exactement juste une convention : si vous utilisez from foobar import * et module foobar ne définit pas un __all__ liste, les noms importés du module ne pas incluent ceux qui sont précédés d'un trait de soulignement. Disons que c'est principalement une convention, puisque ce cas est un coin assez obscur;-).

La convention "leading-underscore" est largement utilisée non seulement pour privé mais aussi pour ce que C++ appellerait protégé par exemple, les noms des méthodes qui sont entièrement destinées à être surchargées par les sous-classes (même celles qui ne peuvent pas être modifiées). ont doivent être surchargées car dans la classe de base, elles raise NotImplementedError !-) sont souvent des noms de sous-titres à une seule tête pour indiquer au code en utilisant les instances de cette classe (ou sous-classes) que lesdites méthodes ne sont pas destiné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, on sous-classe Queue.Queue et on surcharge des méthodes telles que _get y _put ; le "code client" n'appelle jamais ces méthodes ("hook"), mais plutôt les méthodes publiques ("organizing") telles que put y get (c'est ce que l'on appelle le Méthode du modèle modèle de conception -- voir par exemple aquí pour une présentation intéressante basée sur la vidéo d'une de mes conférences sur le sujet, avec l'ajout de synopsis de la transcription).

Edit : Les liens vidéo dans la description des conférences sont maintenant cassés. Vous pouvez trouver les deux premières vidéos aquí y aquí .

2 votes

Alors comment décider si vous devez utiliser _var_name ou utiliser var_name + en l'excluant de __all__ ?

3 votes

@endolith Utilisez le trait de soulignement en tête pour signaler au lecteur de votre code qu'il ne devrait probablement pas l'utiliser (par exemple, parce que vous pourriez le modifier dans la version 2.0, ou même 1.1) ; utilisez explicite __all__ quand vous voulez rendre le module from spam import * convivial (y compris à l'interprète interactif). Donc, la plupart du temps, la réponse est les deux .

0 votes

@AlexMartelli Cette règle liée à l'importation fait-elle l'objet d'une discussion légale quelque part dans les docs ou ailleurs ?

222voto

NickCSE Points 25

._variable est semi-privé et n'est utilisé que par convention.

.__variable est souvent considéré à tort comme superprivé, alors que sa signification réelle est juste de s'associer à empêcher tout accès accidentel [1]

.__variable__ est généralement réservé aux méthodes ou aux variables intégrées

Vous pouvez toujours accéder .__mangled des variables si vous le voulez désespérément. Le double soulignement ne fait que nommer, ou renommer, la variable comme suit instance._className__mangled

Exemple :

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b est accessible car il n'est caché que par convention

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t.__a est introuvable car il n'existe plus à cause du namemangling.

>>> t._Test__a
'a'

En accédant instance._className__variable au lieu du simple nom à double soulignement, vous pouvez accéder à la valeur cachée

0 votes

Mais si "__a" était une variable de classe, alors vous ne pourriez pas y accéder même avec les instructions de la documentation python

0 votes

Pouvez-vous mettre à jour votre réponse avec un exemple de double soulignement par rapport à l'héritage ?

0 votes

._variable d'après les messages ci-dessus et PEP-8, n'est pas seulement une convention : " from M import * n'importe pas les objets dont le nom commence par un trait de soulignement". Cependant, dans le cas présenté en le montrant comme un attribut de classe, cela ne change rien.

19voto

Tim D Points 498

Parfois, vous avez ce qui semble être un tuple avec un trait de soulignement en tête, comme dans le cas suivant

def foo(bar):
    return _('my_' + bar)

Dans ce cas, _() est un alias pour une fonction de localisation qui opère sur le texte pour le mettre dans la bonne langue, etc. en fonction de la locale. Par exemple, Sphinx fait ceci, et vous trouverez parmi les importations

from sphinx.locale import l_, _

et dans sphinx.locale, _() est assigné comme alias d'une fonction de localisation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X