Jakie jest znaczenie pojedynczego i podwójnego podkreślenia przed nazwą obiektu?

Chcę to wyjaśnić raz na zawsze. Czy ktoś może wyjaśnić dokładne znaczenie interlinii przed nazwą obiektu w Pythonie? Wyjaśnij również różnicę między pojedynczym i podwójnym podkreśleniem wiodącym. Ponadto, czy to znaczenie pozostaje takie samo, czy dany obiekt jest zmienną, funkcją, metodą itp?

Author: Ram Rachum, 2009-08-19

13 answers

Pojedynczy Podkreślnik

Nazwy klas z głównym podkreśleniem mają po prostu wskazywać innym programistom, że atrybut lub metoda mają być prywatne. Jednak nic specjalnego nie robi się z samą nazwą.

Cytuję PEP-8:

_single_leading_underscore: słaby wskaźnik "użytku wewnętrznego". Np. from M import * nie importuje obiektów, których nazwa zaczyna się od podkreślenia.

Double Underscore (Name Mangling)

Od the Python docs :

Każdy identyfikator formularza __spam (co najmniej dwa początkowe podkreślniki, co najwyżej jeden końcowy podkreślnik) jest zamieniany tekstowo na _classname__spam, Gdzie classname jest bieżącą nazwą klasy z pozbawionym (- ami) początkowego (- ych) podkreślnika (- ów). To manipulowanie odbywa się bez względu na pozycję składniową identyfikatora, więc może być używane do definiowania zmiennych klasy-prywatnej instancji i klasy, metod, zmiennych przechowywanych w globalach, a nawet zmiennych przechowywanych w instancjach. prywatne do tej klasy na instancjach innych klas.

I ostrzeżenie z tej samej strony:

Name mangling ma na celu zapewnienie klasom łatwego sposobu definiowania" prywatnych " zmiennych i metod instancji, bez konieczności martwienia się o zmienne instancji zdefiniowane przez klasy pochodne, lub mucking ze zmiennymi instancji za pomocą kodu spoza klasy. Zauważ, że zasady manglingu są zaprojektowane głównie po to, aby uniknąć wypadków; nadal jest możliwe, aby zdeterminowana dusza mogła uzyskać dostęp lub zmodyfikować zmienna, która jest uważana za prywatną.

Przykład

>>> 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
Author: Andrew Keeton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-11 20:54:23

Doskonałe odpowiedzi na razie, ale niektórych ciekawostek brakuje. Jeśli używasz from foobar import *, a moduł foobar nie definiuje listy __all__, nazwy zaimportowane z modułu nie zawierają tych, które mają podkreślenie. Powiedzmy, że to głównie konwencja, ponieważ ta sprawa to dość niejasny kąt; -).

Konwencja leading-underscore jest szeroko stosowana nie tylko dlaprywatnych nazw, ale także dla tego, co C++ nazwałby protected - na przykład, nazwy metod, które są w pełni przeznaczone do nadpisywania przez podklasy (nawet te, które mają do nadpisania, ponieważ w klasie bazowej raise NotImplementedError!- ) są często nazwami jednokierunkowymi wskazującymi na kod przy użyciu instancji tej klasy (lub podklas), które nie mają być wywoływane bezpośrednio.

Na przykład, aby utworzyć kolejkę bezpieczną dla wątków z inną dyscypliną kolejkowania niż FIFO, Kolejka importowa, Kolejka podklas._get i _put; "kod klienta" nigdy nie wywołuje tych metod ("hook"), ale raczej ("organizowanie") publicznych metod, takich jak put i get (jest to znane jako metoda szablon wzór projektu -- zobacz np. tutaj dla interesującej prezentacji opartej na wideo mojego wystąpienia na ten temat, z dodatkiem synopsów transkryptu).

 273
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-10 10:05:43

__foo__: Jest to tylko konwencja, sposób, w jaki system Pythona używa nazw, które nie będą sprzeczne z nazwami użytkowników.

_foo: jest to tylko konwencja, sposób dla programisty, aby wskazać, że zmienna jest prywatna (cokolwiek to oznacza w Pythonie).

__foo: ma to prawdziwe znaczenie: interpreter zastępuje tę nazwę _classname__foo, aby upewnić się, że nazwa nie będzie pokrywać się z podobną nazwą w innej klasie.

Żadna inna forma podkreślenia nie ma znaczenia w Python world.

W tych konwencjach nie ma różnicy między klasą, zmienną, globalną itp.

 251
Author: Ned Batchelder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 17:39:32

._variable jest semiprivate i oznacza tylko dla konwencji

.__variable jest często błędnie uważany za superprivate, podczas gdy jego rzeczywiste znaczenie polega na tym, aby namemangle zapobiec przypadkowemu dostępowi[1]

.__variable__ jest zazwyczaj zarezerwowane dla wbudowanych metod lub zmiennych

Nadal możesz uzyskać dostęp do zmiennych .__mangled, jeśli desperacko chcesz. Podwójne podkreślenie tylko namemangles, lub zmienia nazwy, zmienna na coś w rodzaju instance._className__mangled

Przykład:

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

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

T. _b jest dostępny, ponieważ jest ukryty tylko przez Konwencję

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

T._ _ a nie został znaleziony, ponieważ już nie istnieje z powodu namemanglingu

>>> t._Test__a
'a'

Poprzez dostęp do instance._className__variable zamiast tylko podwójnej nazwy podkreślenia, możesz uzyskać dostęp do ukrytej wartości

 182
Author: NickCSE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 10:09:08

Pojedyncze podkreślenie na początku:

Python nie ma prawdziwych prywatnych metod. Zamiast tego jedno podkreślenie na początku nazwy metody lub atrybutu oznacza, że nie powinieneś uzyskiwać dostępu do tej metody, ponieważ nie jest ona częścią 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)

(ten fragment kodu został zaczerpnięty z kodu źródłowego django: django/forms/forms.py). w tym kodzie, errors jest własnością publiczną, ale metoda wywołana przez tę właściwość, _get_errors, jest "prywatna", więc nie powinieneś uzyskiwać dostępu to.

Dwa podkreślenia na początku:

To powoduje wiele zamieszania. Nie powinien być używany do tworzenia prywatnej metody. Należy go użyć, aby uniknąć nadpisania metody przez podklasę lub przypadkowego dostępu do niej. Zobaczmy przykład:
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!

Wyjście:

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

Teraz Utwórz podklasę B i dostosuj metodę _ _ test

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

b = B()
b.test()

Wyjście będzie....

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

Jak widzieliśmy, A. test() nie wywołał B. _ _ test() metody, jak możemy się spodziewać. Ale w rzeczywistości jest to właściwe zachowanie dla __. Dwie metody o nazwie _ _ test() są automatycznie zmieniane na _a _ _ test() i _ B _ _ test (), więc nie są przypadkowo nadpisywane. Kiedy tworzysz metodę zaczynającą się od__, oznacza to, że nie chcesz, aby ktokolwiek mógł ją nadpisać, a zamierzasz uzyskać do niej dostęp tylko z wewnątrz jej własnej klasy.

Dwa podkreślenia na początku i na końcu:

Gdy widzimy metodę taką jak __this__, nie nazywaj tego. Jest to metoda, którą python ma wywoływać, nie ty. Przyjrzyjmy się:

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

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

Zawsze istnieje operator lub natywna funkcja, która wywołuje te magiczne metody. Czasami jest to tylko hak python wywołuje w określonych sytuacjach. Na przykład wywołanie __init__() jest wywołane, gdy obiekt zostanie utworzony po wywołaniu __new__() w celu zbudowania instancji...

Weźmy przykład...
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

Aby uzyskać więcej informacji, zobacz przewodnik PEP-8 . Więcej magicznych metod, zobacz ten PDF .

 90
Author: PythonDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 19:42:09

Czasami masz coś, co wydaje się być krotką z wiodącym podkreśleniem, jak w

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

W tym przypadku chodzi o to, że _() jest aliasem dla funkcji lokalizacyjnej, która operuje na tekście, aby umieścić go w odpowiednim języku itp. na podstawie lokalizacji. Na przykład, Sphinx robi to, a znajdziesz wśród importu

from sphinx.locale import l_, _

I w Sfinksie.locale, _ () jest przypisany jako alias niektórych funkcji lokalizacyjnych.

 15
Author: Tim D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 16:28:22

Podkreślenie (_) w Pythonie

Poniżej znajdują się różne miejsca, w których _ jest używane w Pythonie:

Pojedyncze Podkreślenie:

  • In Interpreter
  • Po nazwie
  • przed imieniem

Podwójne Podkreślenie:

  • __leading_double_underscore

  • Before_after

  • Pojedyncze Podkreślenie

W Interpreter:

_ Zwraca wartość ostatnio wykonanego wyrażenia w Pythonie 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

Dla ignorowania wartości:

Wiele razy nie chcemy zwracać wartości w tym czasie przypisując te wartości do wnderscore. Używany jako zmienna rzutowa.

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

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

Po nazwie

Python ma swoje domyślnie słowa kluczowe, których nie możemy użyć jako nazwy zmiennej. Aby uniknąć takiego konfliktu między słowem kluczowym python a zmienną używamy podkreślenia po nazwie

Przykład:

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

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

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

Przed imieniem

Główny podkreślnik przed nazwą zmiennej / funkcji / metody wskazuje programiście, że jest on przeznaczony tylko do użytku wewnętrznego, który może być modyfikowany w dowolnym momencie klasy.

Tutaj prefiks nazwy przez podkreślenie jest traktowany jako Niepubliczny. Jeśli określ from Import * all nazwa zaczyna się od _ will not import.

Python nie określa prawdziwie prywatnych więc te można wywołać bezpośrednio z innych modułów, jeśli jest określony w wszystkie, nazywamy go również słabym prywatnym

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"

Wywołanie pliku z 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

Podwójny znak podkreślenia mówi interpreterowi Pythona, aby przepisał nazwę w celu uniknięcia konfliktu w podklasie.Interpreter zmienia nazwę zmiennej wraz z rozszerzeniem klasy i tą funkcją znaną jako Mangling. testFile.py

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

Wywołanie z 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

In Mangling interpreter Pythona modyfikuje nazwę zmiennej za pomocą___. Więc wiele razy używa jako członka prywatnego, ponieważ inna klasa nie może uzyskać dostępu do tej zmiennej bezpośrednio. Głównym celem _ _ jest użycie zmiennej / metody w klasie tylko wtedy, gdy chcesz używać jej poza klasą, możesz udostępnić publiczne api

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

Wywołanie z REPL

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

__BEFORE _ AFTER__

Nazwa rozpoczynająca się od _ _ i kończąca się tymi samymi specjalnymi metodami w Pythonie. Python udostępnia te metody do wykorzystania to jako operator przeciążenia w zależności od użytkownika.

Python zapewnia tę konwencję, aby odróżnić funkcję zdefiniowaną przez Użytkownika od funkcji modułu

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

Wywołanie z REPL

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

Numer referencyjny

 10
Author: chirag maliwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-24 16:53:16

Jeśli ktoś naprawdę chce zrobić zmienną tylko do odczytu, IMHO najlepszym sposobem byłoby użycie property() z przekazanym do niej tylko getterem. Dzięki property() możemy mieć pełną kontrolę nad danymi.

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

Rozumiem, że OP zadał trochę inne pytanie, ale ponieważ znalazłem inne pytanie pytające o "jak ustawić zmienne prywatne" oznaczone duplikatem z tym, pomyślałem o dodaniu tej dodatkowej informacji tutaj.

 7
Author: Dev Maha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-15 01:58:14

Pojedyncze podkreślenie wiodące jest konwencją. nie ma różnicy z punktu widzenia interpretera, czy nazwy zaczynają się od pojedynczego podkreślenia, czy nie.

Podwójne podkreślniki prowadzące i końcowe są używane do wbudowanych metod, takich jak __init__, __bool__, itd.

Podwójne podkreślniki wiodące bez końcowych odpowiedników są również konwencją, jednak metody klasy będą zniekształcone przez interpreter. Dla zmiennych lub podstawowych nazw funkcji nie ma różnicy istnieje.

 5
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 17:17:11

Twoje pytanie jest dobre, nie chodzi tylko o metody. Funkcje i obiekty w modułach są zwykle poprzedzone jednym podkreśleniem i mogą być poprzedzone dwoma.

Ale _ _ podwójne _ nazwy podkreślenia nie są zniekształcane w modułach, na przykład. Dzieje się tak, że Nazwy zaczynające się od jednego (lub więcej) podkreślenia nie są importowane, jeśli zaimportujesz wszystkie z modułu (z modułu import*), ani nazwy pokazane w pomocy(moduł).

 3
Author: u0b34a0f6ae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 17:31:04

Oto prosty przykład jak właściwości podwójnego podkreślenia mogą wpływać na dziedziczoną klasę. Tak więc z następującą konfiguracją:

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"

Jeśli następnie utworzysz instancję potomną w REPL Pythona, zobaczysz poniższy

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'
To może być oczywiste dla niektórych, ale zaskoczyło mnie to w znacznie bardziej złożonym środowisku.]}
 3
Author: Marc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 19:15:48

"prywatne" zmienne instancji, do których nie można uzyskać dostępu poza obiektem, nie istnieją w Pythonie. Jednak istnieje konwencja, PO której następuje większość kodu Pythona: nazwa poprzedzona podkreśleniem (np. _spam) powinna być traktowana jako Niepubliczna część API (niezależnie od tego, czy jest to funkcja, metoda czy Element danych). Należy go uznać za szczegółową implementację i może ulec zmianie bez Uwaga.

Odniesienie https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

 3
Author: aptro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-07 17:57:10

Poznanie faktów _ i _ _ jest dość łatwe; Inne odpowiedzi wyrażają je całkiem dobrze. Użycie jest znacznie trudniejsze do określenia.

Tak to widzę:

_

Powinny być użyte do wskazania, że funkcja nie jest przeznaczona do użytku publicznego, jak na przykład API. To i ograniczenie importu sprawiają, że zachowuje się podobnie jak internal w c#.

__

Powinny być używane, aby uniknąć kolizji nazw w hirarchii dziedziczenia i aby uniknąć opóźnień. Podobnie jak prywatne w c#.

==>

Jeśli chcesz zaznaczyć, że coś nie jest do użytku publicznego, ale powinno działać tak, jak protected Użyj _. Jeśli chcesz zaznaczyć, że coś nie jest do użytku publicznego, ale powinno działać tak, jak private użyj __.

Jest to również cytat, który bardzo lubię:

Problem polega na tym, że autor klasy może słusznie myśleć " to nazwa atrybutu/metody powinna być prywatna, dostępna tylko od wewnątrz ta definicja klasy " i używać konwencji _ _ private. Ale później, użytkownik tej klasy może utworzyć podklasę, która dostęp do tego nazwiska. Więc albo superklasa musi zostać zmodyfikowana (co może być trudne lub niemożliwe), lub kod podklasy musi używaj ręcznie zniekształconych nazw (co jest w najlepszym razie brzydkie i kruche).

Ale problem z tym jest moim zdaniem, że jeśli nie ma IDE, które ostrzega cię, gdy nadpisujesz metody, znalezienie błędu może zająć trochę czasu, jeśli przypadkowo nadpisałeś metodę z klasa podstawowa.

 0
Author: Invader,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-04 17:51:49