Question Quelle est la signification d'un simple et double trait de soulignement avant un nom d'objet?


Je veux éclaircir ça une fois pour toutes. Quelqu'un peut-il expliquer la signification exacte d'avoir des traits de soulignement avant le nom d'un objet en Python? Expliquez également la différence entre un trait de soulignement simple et un double. Aussi, cette signification reste-t-elle la même, que l'objet en question soit une variable, une fonction, une méthode, etc.?


981
2017-08-19 17:15


origine


Réponses:


Underscore simple

Les noms, dans une classe, avec un trait de soulignement principal indiquent simplement 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.

Citer PEP-8:

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

Double Underscore (Nom Mangling)

De les docs Python:

Tout identifiant du formulaire __spam (au moins deux traits de soulignement principaux, au plus un trait de soulignement) est remplacé textuellement par _classname__spam, où classname est le nom de la classe actuelle avec le (s) trait (s) de soulignement (s) supprimé (s). Cette opération est effectuée sans tenir compte de la position syntaxique de l'identificateur, de sorte qu'elle peut être utilisée pour définir des variables d'instance et de classe privées, des méthodes, des variables stockées dans des variables globales et même des variables stockées dans des instances. privé à cette classe sur les 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 et des méthodes d'instance "privées", sans avoir à se préoccuper des variables d'instance définies par les classes dérivées, ou du muck avec des variables d'instance. Notez que les règles de mangling 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 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!'}

920
2017-08-19 17:52



Excellentes réponses jusqu'à présent, mais quelques informations manquantes. Un seul soulignement principal n'est pas exactement juste une convention: si vous utilisez from foobar import *et module foobar ne définit pas __all__ liste, les noms importés du module ne pas inclure ceux avec un trait de soulignement principal. Disons que c'est la plupart une convention, puisque ce cas est un coin assez obscur ;-).

La convention leader-underscore est largement utilisée non seulement pour privé noms, mais aussi pour ce que C ++ appellerait protégé ceux - par exemple, les noms de méthodes qui sont entièrement destinées à être remplacées par des sous-classes (même celles qui avoir être remplacé puisque dans la classe de base, ils raise NotImplementedError! -) sont souvent des noms de soulignement unique pour indiquer le code en utilisant 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, sous-classe Queue.Queue et remplace les méthodes telles que _getet _put; "code client" n'appelle jamais les méthodes ("hook"), mais plutôt les méthodes publiques ("organizing") telles que putet get (Ceci est connu comme le Méthode de modèle motif de conception - voir par ex. ici pour une présentation intéressante basée sur une vidéo d'une de mes discussions sur le sujet, avec l'ajout de synopsis de la transcription).


268
2017-08-19 17:21



__foo__: ceci est juste une convention, un moyen pour le système Python d'utiliser des noms qui ne seront pas en conflit avec les noms d'utilisateur.

_foo: ceci 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 une signification réelle: l'interpréteur remplace ce nom par _classname__foo comme un moyen de s'assurer que le nom ne chevauchera pas un nom similaire dans une autre classe.

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

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


245
2017-08-19 17:17



._variable est semiprivate et signifiait juste pour la convention

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

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

Vous pouvez toujours accéder .__mangled variables si vous voulez désespérément. Les doubles underscores juste namemangles, ou rename, 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 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 n'est pas trouvé car il n'existe plus en raison de l'étranglement

>>> t._Test__a
'a'

En accédant instance._className__variable au lieu de juste le nom de double trait, vous pouvez accéder à la valeur cachée


175



Un trait de soulignement simple au début:

Python n'a pas de véritables méthodes privées, donc un 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.

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)

extrait de code extrait du code source de django (django / forms / forms.py). Cela signifie que les erreurs sont une propriété, et cela fait partie du module, mais la méthode que cette propriété appelle, _get_errors, est "private", donc vous ne devriez pas y accéder.

Deux underscores au début:

Cela provoque beaucoup de confusion. Il ne devrait pas être utilisé pour créer une méthode privée. Il devrait être utilisé pour éviter que votre méthode soit surchargée par une sous-classe ou accédée accidentellement. Voyons un exemple:

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

    def test(self):
        self.__test()

a = A()
a.test()

Sortie:

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

Créez maintenant une sous-classe B et personnalisez la méthode __test

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

b = B()
b.test()

La sortie sera ....

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

Comme nous l'avons vu, A.test () n'appelait pas les méthodes B .__ test (), comme on pouvait s'y attendre. Mais en fait, c'est le comportement correct pour __. Ainsi, lorsque vous créez une méthode commençant par __ cela signifie que vous ne voulez pas que quelqu'un puisse la remplacer, elle sera accessible uniquement depuis l'intérieur de sa propre classe.

Deux underscores au début et à la fin:

Quand on voit une méthode comme __this__, ne l'appelle pas. Parce que cela signifie que c'est une méthode que python appelle, pas par vous. Nous allons jeter un coup d'oeil:

>>> 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, c'est juste un appel python hook dans des situations spécifiques. Par exemple __init__()est appelée lorsque l'objet est créé après __new__() est appelé pour 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 Guide PEP-8 aidera plus.

S'il vous plaît trouver plus de méthodes magiques en python ici. https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf


86



Parfois, vous avez ce qui semble être un tuple avec un soulignement principal comme dans

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

Dans ce cas, ce qui se passe est que _ () est un alias pour une fonction de localisation qui fonctionne 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

from sphinx.locale import l_, _

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


15



Underscore (_) en Python

Voici différents endroits où _ est utilisé en Python:

Underscore simple:

  • En Interprète
  • Après un nom
  • Avant un nom

Double Underscore:

  • __leading_double_underscore

  • avant après

  • Underscore simple

En Interprète:

_ renvoie la valeur de la dernière expression exécutée dans 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 ignorer les valeurs:

Plusieurs fois, nous ne voulons pas que les valeurs de retour à ce moment-là assignent ces valeurs à wnderscore. Il a utilisé comme variable jetable.

# 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 un trait de soulignement après le 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
>>>

Avant un nom

Underscore avant le nom de variable / fonction / méthode indique au programmeur qu'il est uniquement destiné à un usage interne, qui peut être modifié chaque fois que la classe le souhaite.

Ici le préfixe de nom par underscore est traité comme non-public. Si spécifier à partir de Import * tout le nom commence par _ ne sera pas importé.

Python ne spécifie pas vraiment privé donc ceux-ci peuvent être appelés directement à partir d'autres modules s'il est spécifié dans tout, 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"

Appel du fichier depuis 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(__)

__leading_double_underscore

Le double trait de soulignement indique à l'interpréteur python de réécrire le nom afin d'éviter les conflits dans la sous-classe. Interpreter modifie le nom de la variable avec l'extension de classe et cette fonctionnalité connue sous le nom de Mangling. testFile.py

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

Appel à partir 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 l'interpréteur Python de Mangling, modifiez le nom de la variable avec ___. Donc, plusieurs fois Il utilise comme membre privé parce qu'une autre classe ne peut pas accéder directement à cette variable. Le but principal de __ est d'utiliser variable / méthode en classe seulement Si vous voulez l'utiliser en dehors de la classe, vous pouvez rendre publique

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

Appel à partir de REPL

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

__AVANT APRÈS__

Le nom commençant par __ et se terminant par le même considère les méthodes spéciales en Python. Python fournit cette méthode pour l'utiliser comme surcharge de l'opérateur en fonction de l'utilisateur.

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

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

Appel à partir de REPL

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

Référence


10



Si l'on veut vraiment faire une variable en lecture seule, à mon humble avis le meilleur moyen serait d'utiliser property () avec seulement getter passé à lui. Avec property () nous pouvons avoir un contrôle complet sur les 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 comme j'ai trouvé une autre question demandant comment 'mettre des variables privées' marquées en double avec celui-ci, j'ai pensé à ajouter cette information supplémentaire ici.


7