Porównaj ceny domen i usług IT, sprzedawców z całego świata

Co oznacza pojedynczy i podwójny podkreślenie przed nazwą obiektu?


Czy ktoś może wyjaśnić dokładne znaczenie podkreślenia wiodącego przed nazwą obiektu w Pythonie i różnicę między nimi?
Czy ta wartość pozostaje niezmieniona niezależnie od tego, czy dany obiekt jest zmienną, funkcją, metodą itp.?
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Jeden znak podkreślenia
>
Nazwy klas z podkreśleniem wiodącym po prostu wskazują innym programistom, że atrybut lub metoda jest przeznaczona do użytku prywatnego. Jednak z samą nazwą nie robi się nic specjalnego.
Zacytować

PEP-8
http://www.python.org/dev/peps/pep-0008/
:

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


Podwójne podkreślenie (zniekształcenie nazwy)
>
Z

dokumenty
https://docs.python.org/3/tuto ... ables
Python :

Każdy identyfikator w postaci
__spam
(co najmniej dwa wiodące podkreślenia, co najwyżej jedno końcowe podkreślenie) jest zastępowany tekstowo przez
_classname__spam
, gdzie
classname
to nazwa aktualnej klasy z przekreślonymi początkowymi podkreśleniami. To zniekształcenie jest wykonywane bez względu na składniową pozycję identyfikatora, więc może być używane do definiowania prywatnej klasy instancji i zmiennych klas, metod, zmiennych przechowywanych w globalnych, a nawet zmiennych przechowywanych w instancjach. zamknięte dla tej klasy na instancjach innych klas.

I ostrzeżenie z tej samej strony:

Manglowanie nazw ma na celu zapewnienie klasom łatwego sposobu definiowania „prywatnych” zmiennych i metod instancji bez martwienia się o zmienne instancji zdefiniowane przez klasy pochodne lub kod poza klasą modyfikuje zmienne instancji. Należy pamiętać, że zasady dotyczące wprowadzania w błąd mają na celu przede wszystkim unikanie wypadków; dusza nadal może uzyskać dostęp lub zmienić zmienną uważaną 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!'}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jak dotąd świetne odpowiedzi, ale brakuje niektórych ciekawostek. Jedynym początkowym podkreśleniem nie jest

po prostu

konwencja: jeśli używasz
from foobar import *
i moduł
foobar
nie definiuje listy
__all__
, nazwy importowane z modułu są

nie

zawierają nazwy z początkowymi podkreśleniami. Powiedzmy, że jest w środku

gruntownie

konwencją, ponieważ ten przypadek jest raczej ciemnym zakątkiem; -).
Początkowa konwencja podkreślenia jest szeroko stosowana nie tylko dla nazw prywatnych, ale także dla tego, co C ++ nazwałoby chronionym-
na przykład nazwy metod, które mają być całkowicie zastąpione przez podklasy (nawet


te, które muszą zostać przesłonięte, ponieważ
podnoszą NotImplementedError
w klasie bazowej! -) są często nazwami z pojedynczym początkowym podkreśleniem, które wskazują kodowi używającemu wystąpień tej klasy (lub podklas), że określone metody nie mają być wywoływane bezpośrednio.


Na przykład, aby utworzyć kolejkę bezpieczną wątkowo z inną dyscypliną kolejkowania niż FIFO, należy zaimportować kolejkę, podklasy Queue.Queue i zastąpić metody, takie jak
_get
i
_put
; „kod klienta” nigdy nie wywołuje tych metod („hook”), ale raczej metody publiczne („organizujące”), takie jak
put
i
get
(jest to znane jako wzorzec projektowy metoda szablonowa - zobacz np. ciekawą prezentację na podstawie wideo z mojej rozmowy na ten temat, z dodatkiem krótkich transkrypcji).
Edycja: linki do wideo w opisie negocjacji już nie działają. Możesz znaleźć pierwsze dwa filmy

tutaj
https://www.youtube.com/watch?v=1Sbzmz1Nxvo
i

tutaj
https://www.youtube.com/watch?v=tJXhtncDBu4
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

__foo__
: To tylko konwencja, sposób, w jaki system Python używa nazw, które nie powodują konfliktów z nazwami użytkowników.
_foo
: To jest tylko konwencja, sposób dla programisty na wskazanie, że zmienna jest prywatna (cokolwiek to oznacza w Pythonie).
__foo
: to robi prawdziwą różnicę: interpreter zastępuje tę nazwę
_classname__foo
, aby upewnić się, że nazwa nie pokrywa się z podobną nazwą w innej klasie.
Żadna inna forma podkreślenia nie ma znaczenia w świecie Pythona.
W tych konwencjach nie ma różnicy między klasą, zmienną, globalną itp.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

._variable
jest półprywatny i służy tylko do celów konwencji
.__variable
is often incorrectly considered superprivate, while it's actual meaning is just to namemangle to

prevent accidental access
[1]
https://www.youtube.com/watch% ... 33m8s
.__variable__
is typically reserved for builtin methods or variables
You can still access
.__mangled
variables if you desperately want to. The double underscores just namemangles, or renames, the variable to something like
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 znaleziono, ponieważ już nie istnieje z powodu pomyłki w nazewnictwie
>>> t._Test__a
'a'

Odwołując się do
instance._className__variable
zamiast prostego podwójnego podkreślenia na nazwie, można uzyskać dostęp do ukrytej wartości
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Jedno podkreślenie na początku

:
Python nie ma prawdziwych prywatnych metod. Zamiast tego pojedynczy znak podkreślenia na początku nazwy metody lub atrybutu oznacza, że ​​nie należy odwoływać się do tej metody, ponieważ nie jest ona częścią interfejsu 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ł pobrany ze źródła django: django/form/forms.py). W tym kodzie
errors
jest własnością publiczną, ale metoda, którą wywołuje ta właściwość, _get_errors, jest „prywatna”, więc nie należy się do niej odwoływać.

Na początku dwa podkreślenia

:
To powoduje wiele zamieszania. Nie należy go używać do tworzenia metody prywatnej. Należy go używać, aby uniknąć przesłonięcia metody przez podklasę lub przypadkowego uzyskania do niej dostępu. Weźmy 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!

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

Teraz podklasa B i skonfiguruj 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 już widzieliśmy, A.test () nie wywołała metod B .__ test (), jak można by się spodziewać. Ale w rzeczywistości jest to prawidłowe zachowanie dla __. Dwie metody o nazwie __test () są automatycznie zmieniane (zniekształcane) na _A__test () i _B__test (), więc nie są one przypadkowo zastępowane. Kiedy tworzysz metodę, która zaczyna się od __, oznacza to, że nie chcesz, aby ktokolwiek mógł ją nadpisać, a będziesz mieć do niej dostęp tylko z własnej klasy.

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

:
Kiedy widzimy metodę taką jak
__this__
, nie wywołuj jej. To jest metoda, którą powinien wywołać Python, a nie ty. Zobaczmy:
>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

Zawsze istnieje operator lub funkcja niestandardowa, która wywołuje te magiczne metody. Czasami jest to tylko podpórka do wywołań Pythona w pewnych sytuacjach. Na przykład
__init __ ()
jest wywoływana, gdy obiekt jest tworzony po wywołaniu
__new __ ()
w celu utworzenia 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 + numbernumber = FalseCalculator(20)
print number + 10 # 10
print number - 20 # 40

Więcej informacji znajdziesz w

przywództwo
https://www.python.org/dev/pep ... ables
PEP-8. Więcej informacji na temat magicznych metod znajdziesz w

ten artykuł PDF
//github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Czasami masz coś, co wydaje się być wiodącą krotką podkreślenia, na przykład
def foo(bar):
return _('my_' + bar)

W tym przypadku _ () jest aliasem funkcji lokalizacyjnej, która operuje na tekście, aby przetłumaczyć go na odpowiedni język itp. W oparciu o ustawienia regionalne. Na przykład Sfinks to robi, a znajdziesz wśród importów
from sphinx.locale import l_, _

aw sphinx.locale _ () jest przypisane jako alias dla niektórych funkcji lokalizacyjnych.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Ponieważ tak wiele osób odnosi się do

występ
https://www.youtube.com/watch% ... 33m8s
Raymonda, ułatwię to trochę, zapisując to, co powiedział:

Zamiar podwójnego podkreślenia nie był związany z prywatnością. Zamierzałem to wykorzystać w ten sposób
class Circle(object): def __init__(self, radius):
self.radius = radius def area(self):
p = self.__perimeter()
r = p/math.pi/2.0
return math.pi * r ** 2.0 def perimeter(self):
return 2.0 * math.pi * self.radius __perimeter = perimeter # local reference
class Tire(Circle): def perimeter(self):
return Circle.perimeter(self) * 1.25


Właściwie to przeciwieństwo prywatności, chodzi o wolność. Dzięki temu Twoje podklasy mogą swobodnie zastępować jedną metodę bez przerywania innych.

.

Załóżmy, że nie przechowujesz lokalnego linku
obwód
w
Circle
. Klasa pochodna
Tire
zastępuje teraz implementację
perimeter
bez dotykania
area
. Kiedy wywołujesz
Tire (5) .area ()
, teoretycznie powinien nadal używać
Circle.perimeter
do obliczeń, ale w rzeczywistości używa
Tire.perimeter
, co nie jest zamierzonym zachowaniem. Dlatego potrzebujemy lokalnego łącza w kręgu. [/code]Ale dlaczego
__perimeter
zamiast
_perimeter
? Ponieważ
_perimeter
nadal daje klasie pochodnej możliwość przesłonięcia:
class Tire(Circle): def perimeter(self):
return Circle.perimeter(self) * 1.25 _perimeter = perimeter

Podwójne podkreślenia mają zniekształcone nazwy, więc jest bardzo mała szansa, że ​​lokalne odwołanie w klasie nadrzędnej zostanie nadpisane w klasie pochodnej. zatem "

sprawia, że ​​Twoje podklasy mogą swobodnie zastępować jedną metodę bez przerywania innych

".
O ile Twoja klasa nie zostanie odziedziczona lub zastąpienie metody niczego nie zepsuje, po prostu nie potrzebujesz
__double_leading_underscore
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Według

https://dbader.org/blog/meanin ... ython
https://dbader.org/blog/meanin ... ython
  • Pojedynczy wiodący podkreślnik (_var) : Konwencja nazewnictwa wskazująca, że ​​nazwa jest przeznaczona do użytku wewnętrznego. Zwykle nie jest używane przez interpreter języka Python (z wyjątkiem importu symboli wieloznacznych) i ma służyć jedynie jako wskazówka dla programisty.
  • Pojedyncze podkreślenie końcowe (var_) : jest używany zgodnie z konwencją, aby uniknąć kolizji nazw ze słowami kluczowymi Pythona.
  • Podwójnie wiodące podkreślenie (__ var) : powoduje uszkodzenie nazwy, gdy jest używane w kontekście klasy. Wymuszone przez interpreter Pythona.
  • Podwójne początkowe i końcowe podkreślenia (__ var__) : wskazuje specjalne metody zdefiniowane przez język Python. Unikaj tego schematu nazewnictwa dla własnych atrybutów.
  • Pojedynczy podkreślenie (_) : jest czasami używane jako nazwa dla zmiennych tymczasowych lub drugorzędnych („Nie obchodzi mnie to”). Zobacz także: wynik ostatniego wyrażenia w REPL w Pythonie.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli naprawdę chcesz, aby zmienna była tylko do odczytu, wtedy IMHO najlepiej jest użyć property (), przekazując do niej tylko metodę pobierającą. 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)

Zdaję sobie sprawę, że OP zadał nieco inne pytanie, ale ponieważ znalazłem inne pytanie z pytaniem „jak ustawić zmienne prywatne” oznaczone duplikatem z tym, pomyślałem o dodaniu tutaj dodatkowych informacji.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Świetne odpowiedzi i wszystkie są poprawne. Podałem prosty przykład wraz z prostą definicją/znaczeniem.
Wartość:
jakaś_zmienna - ► to jest publiczne, każdy może to zobaczyć.
_kilka_zmienna --► w miejscu publicznym ktoś może to zobaczyć, ale jest to konwencja na oznaczenie własnego ...

ostrzeżenie

Python nie wymusza żadnego przymusu.
__some_varaible --► Python zamienia nazwę zmiennej na _classname__some_varaible (zmiana nazwy AKA), co zmniejsza/ukrywa jej widoczność i bardziej przypomina zmienną prywatną.
Szczerze mówiąc, tutaj w

zgodnie z dokumentacją
https://docs.python.org/3/tuto ... ivate
Python

„Prywatne” zmienne instancji, dostęp
które są dostępne tylko z poziomu obiektu, nie istnieją w Pythonie "

Przykład:
class A():
here="abc"
_here="_abc"
__here="__abc"
aObject=A()
print(aObject.here)
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable
#print(aObject.__here)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Pojedyncze wiodące podkreślenia są konwencją. z punktu widzenia tłumacza nie ma znaczenia, czy nazwiska zaczynają się od pojedynczego podkreślenia, czy nie.
Podwójne początkowe i końcowe podkreślenia są używane dla wbudowanych metod, takich jak
__init__
,
__bool__
itp.
Podwójne początkowe podkreślenia bez końcowych odpowiedników są również konwencją, jednak metody klasowe będą

zniekształcony
http://docs.python.org/tutoria ... ables
interpretator. Nie ma różnicy w przypadku zmiennych lub nazw funkcji bazowych.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Twoje pytanie jest dobre, nie chodzi tylko o metody. Funkcje i obiekty w modułach są zwykle poprzedzone jednym podkreśleniem, a także mogą być poprzedzone dwoma.
Ale nazwy __double_underscore nie są zniekształcane w modułach, np. Dzieje się tak, że nazwy zaczynające się od jednego (lub więcej) podkreślenia nie są importowane, jeśli importujesz wszystko z modułu (z modułu import *), a także nazwy wyświetlane w pomocy (moduł).
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto prosty przykład ilustrujący, jak właściwości podwójnego podkreślenia mogą wpływać na dziedziczoną klasę. Tak więc przy następującej konfiguracji:
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ę podrzędną w pythonowym REPL, zobaczysz następujące
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'

Dla niektórych może to być oczywiste, ale zaskoczyło mnie to w znacznie bardziej złożonym otoczeniu.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

„Prywatne” zmienne instancji, do których można uzyskać dostęp tylko z poziomu obiektu, nie istnieją w Pythonie. Istnieje jednak konwencja, której przestrzega większość kodu w Pythonie: nazwa poprzedzona podkreśleniem (na przykład _spam) powinna być traktowana jako niepubliczna część interfejsu API (czy to funkcja, metoda czy element danych). Należy to traktować jako szczegół implementacji i może ulec zmianie bez powiadomienia.
połączyć

https://docs.python.org/2/ tutorial/classes.html # private-variable-and-class-local-reference
https://docs.python.org/2/tuto ... ences
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Fakty _ i __ są dość łatwe do uzyskania; inne odpowiedzi dobrze je wyrażają. Użycie jest znacznie trudniejsze do zdefiniowania.
Tak to widzę:
_

Powinien być używany do wskazania, że ​​funkcja nie jest przeznaczona do użytku publicznego, na przykład interfejs API. To oraz ograniczenie importu sprawiają, że zachowuje się on bardzo podobnie do
wewnętrznego
w języku c #.
__

Powinien być używany w celu uniknięcia kolizji nazw w dziedziczeniu hirarchicznym i późnego wiązania. Bardzo podobny do prywatnego w C #. rok
==>
Jeśli chcesz wskazać, że coś nie jest przeznaczone do użytku publicznego, ale powinno działać jako
protected
, użyj
_
.
Jeśli chcesz wskazać, że coś nie jest do użytku publicznego, ale powinno działać jak
private
, użyj
__
.
To również cytat, który bardzo mi się podoba:

Problem w tym, że autor zajęć może zasadnie myśleć, że „to
nazwa atrybutu/metody musi być prywatna, dostępna tylko z
ta definicja klasy ”i użyj konwencji __private. Ale później ...,
użytkownik tej klasy może utworzyć podklasę, której jest to uzasadnione
w dostępie do tej nazwy. Zatem albo superklasa musi zostać zmieniona
(co może być trudne lub niemożliwe), a kod podklasy powinien
używaj ręcznie zniekształconych nazw (co jest w najlepszym przypadku brzydkie i delikatne).

Ale problem z tym polega na tym, że moim zdaniem, jeśli nie ma IDE, które ostrzega, kiedy zastępujesz metody, znalezienie błędu może zająć trochę czasu, jeśli przypadkowo przesłonisz metodę z klasy bazowej.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się