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

je veux clarifier ça une fois pour toutes. Quelqu'un peut-il s'il vous plaît expliquer la signification exacte d'avoir des underscores menant avant le nom d'un objet en Python? Aussi expliquer la différence entre un simple et un double trait de soulignement. En outre, ce sens reste-t-il le même, que l'objet en question soit une variable, une fonction, une méthode, etc.?

1015
demandé sur Ram Rachum 2009-08-19 21:11:57

13 réponses

L'Unique Trait De Soulignement

les noms, dans une classe, avec un underscore principal sont simplement pour indiquer aux autres programmeurs que l'attribut ou la méthode est destinée à être privée. Cependant, rien de spécial n'est fait avec le nom lui-même.

pour citer PEP-8 :

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

Double Trait De Soulignement (Name Mangling)

à Partir de le Python docs :

tout identificateur du formulaire __spam (au moins deux caractères de soulignement principaux, au plus un caractère de soulignement de queue) est textuellement remplacé par _classname__spam , où classname est le nom de classe actuel avec caractère de soulignement de queue. Cette mutilation est faite sans égard à la position syntaxique de l'identifiant, de sorte qu'il peut être utilisé pour définir les variables Classe-instance privée et classe, les méthodes, les variables stockées dans les globals, et même les variables stockées dans les instances. privé de cette classe sur les instances d'autres classes.

et un avertissement de la même page:

nom mangling est destiné à donner aux classes un moyen facile de définir des variables et des méthodes d'instance "privées", sans avoir à se soucier les variables d'instance définies par les classes dérivées, ou le mucking avec les variables d'instance par le code en dehors de la classe. Notez que les règles de mutilation 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!'}
942
répondu Andrew Keeton 2013-02-11 20:54:23

Excellentes réponses jusqu'à présent, mais certaines anecdotes sont manquants. Un simple underscore de tête n'est pas exactement juste une convention: si vous utilisez from foobar import * , et le module foobar ne définit pas une liste __all__ , les noms importés du module ne pas inclure ceux avec un underscore de tête. Disons que c'est principalement une convention, puisque cette affaire est un coin assez obscur;-).

La Convention leading-underscore est largement utilisée non seulement pour les noms privés , mais aussi pour ce que C++ appellerait protégés , par exemple, les noms de méthodes qui sont entièrement destinées à être supplantées par des sous-classes (même celles qui ont à supplanter puisque dans la classe de base ils raise NotImplementedError !- ) sont souvent des noms de soulignement à un seul caractère pour indiquer le code en utilisant les instances de cette classe (ou sous-classes) que ces méthodes ne sont pas censées être appelées directement.

par exemple, pour faire une file d'attente sans fil avec une discipline de file d'attente différente de FIFO, On importe File, sous-classe File.File d'attente, et remplace des méthodes telles que _get et _put ; "code client" n'appelle jamais ces ("crochet") méthodes, mais plutôt les ("organisation") méthodes publiques telles que put et get (ceci est connu sous le nom de Template Method modèle de conception -- voir, par exemple, ici pour une présentation intéressante basée sur une vidéo d'un discours de la mine sur le sujet, avec le plus de résumés de la transcription).

273
répondu Alex Martelli 2013-06-10 10:05:43

__foo__ : c'est juste une convention, une façon pour le système Python d'utiliser des noms qui n'entrent pas en conflit avec les noms d'utilisateurs.

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

__foo : ceci a un sens réel: l'interprète remplace ce nom par _classname__foo pour s'assurer que le nom ne se chevauchera pas avec un nom similaire dans une autre classe.

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

il n'y a pas de différence entre Classe, variable, globale, etc. dans ces conventions.

251
répondu Ned Batchelder 2009-08-19 17:39:32

._variable est semi-privées et destinés seulement pour la convention

.__variable est souvent considéré à tort comme superprivé, alors que son sens réel est juste à namemangle à empêcher l'accès accidentel [1]

.__variable__ est typiquement réservé aux méthodes ou variables intégrées

vous pouvez toujours accéder aux variables .__mangled si vous le voulez désespérément. Le double souligne juste namemangles, ou renames, la variable à quelque chose comme 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 parce qu'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 n'est pas trouvé parce qu'il n'existe plus en raison de namemangling

>>> t._Test__a
'a'

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

182
répondu NickCSE 2016-05-17 10:09:08

simple soulignement au début:

Python n'a pas de vraies méthodes privées. Au lieu de cela, un underscore au début d'un nom de méthode ou d'attribut signifie que vous ne devriez pas accéder à cette méthode, parce qu'elle ne fait pas partie de l'API.

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(cet extrait de code provient du code source de django: django/forms/forms.py). Dans ce code, errors est un bien public, mais la méthode que cette propriété appelle, _get_errors, est "privé", donc vous ne devriez pas y accéder.

deux soulignements au début:

cela cause beaucoup de confusion. Il ne devrait pas être utilisé pour créer une méthode privée. Il doit être utilisé pour éviter que votre méthode soit dépassée par une sous-classe ou accessible accidentellement. Voyons un exemple:

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

sortie:

$ python test.py
I'm test method in class A
I'm test method in class A

créer maintenant une sous-Classe B et faire la personnalisation pour _ _ la méthode d'essai

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

sortie sera....

$ python test.py
I'm test method in class A

comme nous l'avons vu, A. test() n'a pas appelé B.__test() méthodes, comme nous pourrions nous attendre. Mais en fait, c'est le comportement correct pour __. Les deux méthodes appelées _ _ test () sont automatiquement renommées en _a__test() et _B__test(), de sorte qu'elles ne se substituent pas accidentellement. Lorsque vous créez une méthode en commençant par __ cela signifie que vous ne voulez pas que quiconque soit en mesure de le remplacer, et vous souhaitez accéder à partir de l'intérieur de sa propre classe.

deux soulignements au début et à la fin:

quand on voit une méthode comme __this__ , ne l'appelez pas. C'est une méthode que python est censé appeler, pas vous. Regardons:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

Il y a toujours un opérateur ou une fonction native qui appelle ces méthodes magiques. Parfois, il suffit d'un crochet appels python dans des situations spécifiques. Par exemple __init__() est appelée lorsque l'objet est créé après __new__() est appelé à construire l'instance...

prenons un exemple...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

pour plus de détails, voir le PEP-8 guide . Pour plus de méthodes magiques, voir Ce PDF .

90
répondu PythonDev 2018-08-21 19:42:09

parfois vous avez ce qui semble être un tuple avec un underscore de direction comme dans

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

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 bonne langue, etc. basé sur les paramètres régionaux. Par exemple, Sphinx fait cela, et vous trouverez parmi les importations""

from sphinx.locale import l_, _

et en sphinx.locale, _ () est un alias d'une fonction de localisation.

15
répondu Tim D 2012-01-11 16:28:22

trait de Soulignement (_) dans Python

ci-dessous sont différents endroits où _ est utilisé en Python:

L'Unique Trait De Soulignement:

  • L'Interprète
  • après un nom
  • avant un nom

Trait De Soulignement Double:

  • __en tête _ double _ underscore

  • avant-après

  • L'Unique Trait De Soulignement

L'Interprète:

_ renvoie la valeur de la dernière expression exécutée en Python REPL

>>> a = 10
>>> b = 10
>>> _
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> a+b
20
>>> _
20
>>> _ * 2
40
>>> _
40
>>> _ / 2
20

Pour ne pas tenir compte des valeurs:

Plusieurs fois, nous ne voulons pas les valeurs de retour à l'époque attribuer ces valeurs à wnderscore. Il a utilisé comme variable throwaway.

# Ignore a value of specific location/index
for _ in rang(10)
    print "Test"

# Ignore a value when unpacking
a,b,_,_ = my_method(var1)

après un nom

Python a leurs mots-clés par défaut que nous ne pouvons pas utiliser comme nom de variable. Pour éviter un tel conflit entre le mot-clé python et la variable, nous utilisons underscore après nom

exemple:

>>> class MyClass():
...     def __init__(self):
...             print "OWK"

>>> def my_defination(var1 = 1, class_ = MyClass):
...     print var1
...     print class_

>>> my_defination()
1
__main__.MyClass
>>>

devant un nom

pointer un caractère de soulignement avant le nom de la variable/fonction / méthode indique au programmeur que c'est pour usage interne seulement, qui peut être modifié chaque fois que la classe veut.

ici le préfixe de nom par underscore est traité comme non-public. Si spécifiez De L'Import * tout le nom commence par _ ne sera pas importation.

Python ne spécifie pas vraiment privé donc celui-ci peut être appelé directement à partir d'autres modules s'il est spécifié dans all , nous l'appelons aussi faible privé

class Prefix:
...     def __init__(self):
...             self.public = 10
...             self._private = 12
>>> test = Prefix()
>>> test.public
10
>>> test._private
12
Python class_file.py

def public_api():
    print "public api"

def _private_api():
    print "private api"

fichier appelant de REPL

>>> from class_file import *
>>> public_api()
public api

>>> _private_api()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_private_api' is not defined

>>> import class_file
>>> class_file.public_api()
public api
>>> class_file._private_api()
private api
Double Underscore(__)

__en tête_double_underscore

diriger double underscore dire à l'interpréteur python de réécrire le nom afin d'éviter les conflits dans la sous-classe.L'interpréteur change le nom de la variable avec l'extension de classe et cette caractéristique connue sous le nom de Mangling. testFile.py

class Myclass():
    def __init__(self):
        self.__variable = 10

l'Appel de REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__variable
Traceback (most recent call last):
File "", line 1, in
AttributeError: Myclass instance has no attribute '__variable'
nce has no attribute 'Myclass'
>>> obj._Myclass__variable
10

dans Mangling Python interpreter modifier le nom de la variable avec ___. Ainsi, il utilise plusieurs fois en tant que membre privé parce qu'une autre classe ne peut pas accéder à cette variable directement. Le but principal pour _ _ est d'utiliser la variable / méthode dans la classe seulement si vous voulez l'utiliser en dehors de la classe que vous pouvez rendre publique api

class Myclass():
    def __init__(self):
        self.__variable = 10
    def func(self)
        print self.__variable

l'Appel de REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.func()
10

_ _ AVANT _ APRÈS _ _ _

Nom avec démarrer avec _ _ et se termine avec les mêmes considerations méthodes spéciales en Python. Python fournir ces méthodes à utiliser comme la surcharge d'opérateur en fonction de l'utilisateur.

Python fournit cette convention pour différencier la fonction définie par l'utilisateur avec la fonction du module

class Myclass():
    def __add__(self,a,b):
        print a*b

l'Appel de REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__add__(1,2)
2
>>> obj.__add__(5,2)
10

référence

10
répondu chirag maliwal 2018-03-24 16:53:16

si l'on veut vraiment faire une variable en lecture seule, IMHO le meilleur moyen serait d'utiliser la propriété() avec seulement getter passé à elle. Avec property () nous pouvons avoir le contrôle complet des données.

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

je comprends que OP a posé une question un peu différente mais puisque j'ai trouvé une autre question demandant 'comment définir des variables privées' dupliqué marqué avec celui-ci, j'ai pensé à ajouter cette information supplémentaire ici.

7
répondu Dev Maha 2013-04-15 01:58:14

Seul principaux traits de soulignement est une convention. il n'y a pas de différence du point de vue de l'interprète si les noms commencent par un simple underscore ou non.

double tête et soulignement arrière sont utilisés pour les méthodes intégrées, telles que __init__ , __bool__ , etc.

double tête souligne w/o homologues arrière sont une convention trop, cependant, les méthodes de classe sera mutilé par le interprète. Pour les variables ou les noms de fonction de base, aucune différence n'existe.

5
répondu SilentGhost 2009-08-19 17:17:11

votre question Est Bonne, il ne s'agit pas seulement de méthodes. Les fonctions et les objets dans les modules sont généralement préfixés avec un underscore, et peuvent être préfixés par deux.

Mais __double_soulignent les noms ne sont pas de nom de déformation dans les modules, par exemple. Ce qui se passe, c'est que les noms commençant par un (ou plusieurs) soulignements ne sont pas importés si vous importez tout à partir d'un module (à partir du module import*), pas plus que les noms ne sont affichés dans help(module).

3
répondu u0b34a0f6ae 2009-08-19 17:31:04

voici un exemple simple sur la façon dont les propriétés de soulignement double peuvent affecter une classe héritée. Ainsi, avec la configuration suivante:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

si vous créez alors une instance enfant dans la version python, vous verrez ci-dessous

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

c'est peut-être évident pour certains, mais cela m'a pris au dépourvu dans un environnement beaucoup plus complexe

3
répondu Marc 2014-08-22 19:15:48

les variables d'instance "privées" qui ne peuvent être accédées que de l'intérieur d'un objet n'existent pas en Python. Cependant, il existe une convention qui est suivie par la plupart des codes Python: un nom préfixé avec un caractère 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 de mise en œuvre et peut être modifié sans préavis.

de référence https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

3
répondu aptro 2015-02-07 17:57:10

les faits de _ et _ _ _ _ est assez facile; les autres réponses exprimer assez bien. L'utilisation est beaucoup plus difficile à déterminer.

C'est comme ça que je le vois:

_

doit être utilisé pour indiquer qu'une fonction n'est pas destinée au public comme par exemple une API. Ceci et la restriction à l'importation LA FONT se comporter un peu comme internal dans c#.

__

doit être utilisé pour éviter la collision de nom dans le héritace hirarchy et pour éviter latebinding. Un peu comme privé en c#.

= = >

si vous voulez indiquer que quelque chose n'est pas destiné à l'usage public, mais il doit agir comme protected utiliser _ . Si vous voulez indiquer que quelque chose n'est pas à l'usage du public, mais il doit agir comme private utiliser __ .

C'est aussi une citation que j'aime beaucoup:

le problème est que l'auteur d'une classe, on peut légitimement penser "ce attribut / nom de la méthode doit être privé, accessible seulement de l'intérieur cette définition de la classe" et utiliser la _ _ _ convention privée. Mais plus tard, un utilisateur de cette classe peut créer une sous-classe qui a légitimement besoin l'accès à ce nom. Donc soit la superclasse doit être modifiée (qui peut être difficile ou impossible), ou le code de la sous-classe doit utilisez des noms mutilés manuellement (ce qui est laid et fragile au mieux).

mais le problème avec cela est à mon avis que s'il n'y a pas D'IDE qui vous prévient lorsque vous outrepassez les méthodes, trouver l'erreur pourrait vous prendre un certain temps si vous avez accidentellement outrepasser une méthode d'une classe de base.

0
répondu Invader 2017-11-04 17:51:49