Frage Was bedeutet ein einfacher und ein doppelter Unterstrich vor einem Objektnamen?


Ich möchte das ein für allemal klären. Kann jemand bitte die genaue Bedeutung von führenden Unterstrichen vor dem Namen eines Objekts in Python erklären? Erläutern Sie auch den Unterschied zwischen einem einzelnen und einem doppelten führenden Unterstrich. Bleibt diese Bedeutung auch gleich, unabhängig davon, ob es sich bei dem Objekt um eine Variable, eine Funktion, eine Methode usw. handelt?


981
2017-08-19 17:15


Ursprung


Antworten:


Einzelner Unterstrich

Namen in einer Klasse mit einem führenden Unterstrich sollen anderen Programmierern einfach anzeigen, dass das Attribut oder die Methode privat sein soll. Mit dem Namen selbst wird jedoch nichts Besonderes gemacht.

Zitieren PEP-8:

_single_leading_underscore: schwacher Indikator für "interne Verwendung". Z.B. from M import * importiert keine Objekte, deren Name mit einem Unterstrich beginnt.

Doppelter Unterstrich (Name Mangling)

Von die Python-Dokumente:

Beliebige Kennung des Formulars __spam (mindestens zwei führende Unterstriche, höchstens ein abschließender Unterstrich) wird textuell durch ersetzt _classname__spam, woher classname ist der Name der aktuellen Klasse, wobei die führenden Unterstriche entfernt werden. Dieses Mangeln erfolgt ohne Rücksicht auf die syntaktische Position des Bezeichners, so dass es verwendet werden kann, um klassenprivate Instanz- und Klassenvariablen, Methoden, in globalen Variablen gespeicherte Variablen und sogar in Instanzen gespeicherte Variablen zu definieren. Diese Klasse ist für Instanzen anderer Klassen privat.

Und eine Warnung von derselben Seite:

Der Name mangling soll Klassen eine einfache Möglichkeit geben, "private" Instanzvariablen und -methoden zu definieren, ohne sich um von abgeleiteten Klassen definierte Instanzvariablen kümmern oder mit Instanzvariablen nach Code außerhalb der Klasse mucken zu müssen. Beachten Sie, dass die Mangelnde Regeln vor allem darauf ausgelegt sind, Unfälle zu vermeiden; Es ist immer noch möglich, dass eine entschlossene Seele auf eine Variable zugreift oder sie ändert, die als privat betrachtet wird.

Beispiel

>>> 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



Ausgezeichnete Antworten bisher, aber einige Leckerbissen fehlen. Ein einzelner führender Unterstrich ist nicht genau gerade eine Konvention: wenn Sie verwenden from foobar import *und Modul foobar definiert kein __all__ Liste, die Namen aus dem Modul importiert unterlassen Sie enthalten Sie diejenigen mit einem führenden Unterstrich. Sagen wir es so meist eine Konvention, da dieser Fall eine ziemlich obskure Ecke ist ;-).

Die Leading-Understring-Konvention wird nicht nur für Privatgelände Namen, sondern auch für das, was C ++ aufrufen würde geschützt Einsen - zum Beispiel Namen von Methoden, die vollständig von Unterklassen überschrieben werden sollen (auch solche, die haben in der Basisklasse überschrieben werden raise NotImplementedError! -) sind oft Single-Leading-Underscore-Namen, um anzugeben, um zu codieren verwenden Instanzen dieser Klasse (oder Unterklassen), für die diese Methoden nicht direkt aufgerufen werden sollen.

Um beispielsweise eine thread-sichere Warteschlange mit einer anderen Warteschlangendisziplin als FIFO zu erstellen, importiert man Queue, Unterklassen Queue.Queue und überschreibt solche Methoden wie _getund _put; "client code" ruft niemals diese ("hook") Methoden auf, sondern die ("organisierenden") öffentlichen Methoden wie putund get (Dies ist bekannt als die Vorlagenmethode Entwurfsmuster - siehe z.B. Hier für eine interessante Präsentation basierend auf einem Video von einem Vortrag von mir zu dem Thema, mit der Ergänzung von Übersichten der Abschrift).


268
2017-08-19 17:21



__foo__: Dies ist nur eine Konvention, eine Möglichkeit für das Python-System, Namen zu verwenden, die nicht mit Benutzernamen kollidieren.

_foo: Dies ist nur eine Konvention, eine Möglichkeit für den Programmierer anzugeben, dass die Variable privat ist (was auch immer das in Python bedeutet).

__foo: Das hat echte Bedeutung: Der Interpreter ersetzt diesen Namen mit _classname__foo als eine Möglichkeit, sicherzustellen, dass der Name nicht mit einem ähnlichen Namen in einer anderen Klasse überlappt.

Keine andere Form von Unterstrichen hat in der Python-Welt eine Bedeutung.

In diesen Konventionen gibt es keinen Unterschied zwischen Klasse, Variable, global usw.


245
2017-08-19 17:17



._variable ist halbprivat und nur für Kongresse gedacht

.__variable wird oft fälschlicherweise für überprivilegiert gehalten, während es eigentlich nur um Namensgebung geht verhindern Sie den versehentlichen Zugriff[1]

.__variable__ ist typischerweise für eingebaute Methoden oder Variablen reserviert

Sie können immer noch darauf zugreifen .__mangled Variablen, wenn Sie verzweifelt wollen. Der Doppelstrich unterstreicht nur die Namen oder benennt die Variable in etwas Ähnliches um instance._className__mangled

Beispiel:

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

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

t._b ist zugänglich, da es nur durch Konvention versteckt ist

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

t .__ a wird nicht gefunden, weil es aufgrund der Namensgebung nicht mehr existiert

>>> t._Test__a
'a'

Durch den Zugriff instance._className__variable Sie können nicht nur auf den Namen des doppelten Unterstrichs zugreifen, sondern auch auf den versteckten Wert


175



Einfacher Unterstrich am Anfang:

Python hat keine echten privaten Methoden. Ein Unterstrich am Anfang eines Methoden- oder Attributnamens bedeutet, dass Sie nicht auf diese Methode zugreifen sollten, da sie nicht Teil der API ist.

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)

Code-Snippet aus dem Django-Quellcode (django / forms / forms.py). Das bedeutet, Fehler sind eine Eigenschaft und Teil des Moduls, aber die Methode, die diese Eigenschaft _get_errors aufruft, ist "privat", weshalb Sie nicht darauf zugreifen sollten.

Zwei Unterstriche am Anfang:

Dies verursacht viel Verwirrung. Es sollte nicht zum Erstellen einer privaten Methode verwendet werden. Es sollte verwendet werden, um zu vermeiden, dass Ihre Methode von einer Unterklasse außer Kraft gesetzt oder versehentlich darauf zugegriffen wird. Lass uns ein Beispiel sehen:

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

    def test(self):
        self.__test()

a = A()
a.test()

Ausgabe:

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

Erstellen Sie nun eine Unterklasse B und führen Sie die Anpassung für die __test-Methode durch

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

b = B()
b.test()

Ausgabe wird .... sein

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

Wie wir gesehen haben, hat A.test () nicht B .__ test () -Methoden aufgerufen, wie wir erwarten können. Aber das ist das richtige Verhalten für __. Wenn Sie also eine Methode erstellen, die mit __ beginnt, bedeutet dies, dass Sie nicht möchten, dass jemand sie überschreibt, sondern nur innerhalb der eigenen Klasse.

Zwei Unterstriche am Anfang und am Ende:

Wenn wir eine Methode wie sehen __this__nenn es nicht. Weil es bedeutet, dass es eine Methode ist, die Python aufruft, nicht von Ihnen. Lass uns einen Blick darauf werfen:

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

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

Es gibt immer eine Operator- oder native Funktion, die diese magischen Methoden aufruft. Manchmal ist es nur ein Haken, den Python in bestimmten Situationen aufruft. Beispielsweise __init__()wird aufgerufen, wenn das Objekt danach erstellt wird __new__() ist aufgerufen, die Instanz zu bauen ...

Nehmen wir ein Beispiel ...

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

Für mehr Details PEP-8 Anleitung wird mehr helfen.

Hier finden Sie mehr magische Methoden in Python. https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf


86



Manchmal haben Sie ein Tupel mit einem führenden Unterstrich wie in

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

In diesem Fall ist _ () ein Alias ​​für eine Lokalisierungsfunktion, die basierend auf dem Gebietsschema Text verarbeitet, um ihn in die richtige Sprache usw. zu bringen. Zum Beispiel macht Sphinx dies, und Sie werden unter den Importen finden

from sphinx.locale import l_, _

und in sphinx.locale wird _ () als Alias ​​einer Lokalisierungsfunktion zugewiesen.


15



Underscore (_) in Python

Im Folgenden finden Sie verschiedene Orte, an denen _ in Python verwendet wird:

Single Underscore:

  • Im Dolmetscher
  • Nach einem Namen
  • Vor einem Namen

Doppelter Unterstrich:

  • __leading_double_underscore

  • vorher Nachher

  • Einzelner Unterstrich

Im Dolmetscher:

_ gibt den Wert des zuletzt ausgeführten Ausdrucks in Python REPL zurück

>>> 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

Um Werte zu ignorieren:

Mehrfache Zeit, die wir keine Rückgabewerte wünschen, weisen diese Werte wnderscore zu. Es wurde als Wegwerfvariable verwendet.

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

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

Nach einem Namen

Python hat standardmäßig ihre Schlüsselwörter, die wir nicht als Variablennamen verwenden können. Um einen solchen Konflikt zwischen Python-Schlüsselwort und -Variable zu vermeiden, verwenden wir Unterstrich nach Name

Beispiel:

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

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

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

Vor einem Namen

Führender Underscore vor dem Namen der Variable / function / method zeigt dem Programmierer an, dass er nur für den internen Gebrauch bestimmt ist und dass er geändert werden kann, wann immer die Klasse möchte.

Hier wird das Namenspräfix durch Unterstrich als nicht öffentlich behandelt. Bei Angabe von Import * wird der gesamte Name, der mit _ beginnt, nicht importiert.

Python spezifiziert nicht wirklich private, so dass diese direkt von anderen Modulen aufgerufen werden können, wenn es in angegeben ist alleWir nennen es auch schwach Private

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"

Datei von REPL aufrufen

>>> 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

Führender doppelter Unterstrich besagt, dass der Python-Interpreter den Namen umschreiben soll, um Konflikte in der Unterklasse zu vermeiden.Interpreter ändert den Variablennamen mit der Klassenerweiterung und dem Feature, das als Mangling bekannt ist. testFile.py

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

Anruf von 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

Im Mangling-Python-Interpreter ändern Sie den Variablennamen mit ___. Also mehrere Zeit es als private Mitglied verwenden, weil eine andere Klasse nicht direkt auf diese Variable zugreifen kann. Hauptzweck für __ ist die Verwendung der Variablen / Methode nur in der Klasse. Wenn Sie sie außerhalb der Klasse verwenden möchten, können Sie sie öffentlich machen

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

Anruf von REPL

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

__VORHER NACHHER__

Name mit Start mit __ und endet mit Same berücksichtigt spezielle Methoden in Python. Python stellt diese Methoden zur Verfügung, um es abhängig vom Benutzer als Überlastung des Operators zu verwenden.

Python bietet diese Konvention, um zwischen der benutzerdefinierten Funktion und der Modulfunktion zu unterscheiden

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

Anruf von REPL

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

Referenz


10