Czy ktoś może wyjaśnić dokładne znaczenie wiodących znaków podkreślenia przed nazwą obiektu w Pythonie i różnicę między nimi?
Ponadto, czy to znaczenie pozostaje takie samo, czy przedmiotowy obiekt jest zmienną, funkcją, metodą itp.?
python
oop
naming-conventions
ivanleoncz
źródło
źródło
Odpowiedzi:
Pojedynczy podkreślnik
Nazwy w klasie z wiodącym podkreśleniem mają po prostu wskazywać innym programistom, że atrybut lub metoda mają być prywatne. Jednak sama nazwa nie robi nic specjalnego.
Cytując PEP-8 :
Podwójny znak podkreślenia (zarządzanie nazwami)
Z dokumentacji Pythona :
I ostrzeżenie z tej samej strony:
Przykład
źródło
__
podwójnego podkreślenia jako nazwy zmiennej? jaka, __ = foo()
Jak dotąd doskonałe odpowiedzi, ale brakuje niektórych ciekawostek. Pojedyncza wiodącym podkreślenia nie jest dokładnie tylko konwencja: jeśli używasz
from foobar import *
, a modułfoobar
nie definiuje__all__
listę nazwy importowane z modułu nie obejmują tych z wiodących podkreślenia. Powiedzmy, że jest to głównie konwencja, ponieważ ta sprawa jest dość niejasnym zakątkiem ;-).Konwencja wiodącego podkreślenia jest szeroko stosowana nie tylko dla nazw prywatnych , ale także dla tego, co C ++ nazwałby chronionymi - na przykład, nazw metod, które są całkowicie przeznaczone do zastąpienia przez podklasy (nawet te, które należy zastąpić, ponieważ w klasa podstawowa one
raise NotImplementedError
! -) są często pojedynczymi wiodącymi znakami podkreślenia, które wskazują kodowi za pomocą instancji tej klasy (lub podklas), że wspomniane metody nie powinny być wywoływane bezpośrednio.Na przykład, aby utworzyć kolejkę bezpieczną dla wątków z inną dyscypliną kolejkowania niż FIFO, jedna importuje kolejkę, podklasę kolejki. Kolejkę i zastępuje takie metody jak
_get
i_put
; „kod klienta” nigdy nie wywołuje tych metod („przechwytujących”), ale raczej metody publiczne („organizujące”), takie jakput
iget
(jest to znane jako wzorzec projektowy metody szablonowej - patrz np. tutaj na interesującą prezentację opartą na filmie mojego wystąpienia na ten temat, z dodatkiem streszczenia transkryptu).Edycja: Łącza wideo w opisie rozmów są teraz zepsute. Możesz znaleźć dwa pierwsze filmy tutaj i tutaj .
źródło
_var_name
czy użyćvar_name
+ wykluczenia__all__
?__all__
gdy chcesz, aby moduł byłfrom spam import *
przyjazny (w tym w interaktywnym tłumaczu). Tak więc przez większość czasu odpowiedź jest obie ._
prywatne . Najwyraźniej mówię o analogiach, ponieważ w Pythonie nic nie jest naprawdę prywatne . Podczas nurkowania w semantyce Powiedziałbym możemy krawat_
do Javy chroniony od proctected „klas pochodnych i / lub wewnątrz tego samego pakietu” w pomocy Java. Zamień pakiet na moduł, ponieważ PEP8 mówi nam już, że_
nie jest to tylko konwencja, gdy mówimy o*
imporcie i masz go. I zdecydowanie__
byłby równoważny prywatnej Javie, gdy mówimy o identyfikatorach w klasie.__foo__
: to tylko konwencja, sposób, w jaki system Python może używać nazw, które nie będą powodować konfliktów z nazwami użytkowników._foo
: to tylko konwencja, sposób dla programisty na wskazanie, że zmienna jest prywatna (cokolwiek to znaczy w Pythonie).__foo
: to ma prawdziwe znaczenie: interpreter zastępuje tę nazwę_classname__foo
jako sposób, aby nazwa nie nakładała się na podobną nazwę w innej klasie.Żadna inna forma podkreślenia nie ma znaczenia w świecie Python.
W tych konwencjach nie ma różnicy między klasą, zmienną, globalną itp.
źródło
__foo
i ciekawy. Jak może nakładać się na podobne nazwy metod z innymi klasami? Mam na myśli, że nadal musisz uzyskać do niego dostępinstance.__foo()
(jeśli nie zostałby zmieniony przez tłumacza), prawda?from module import *
nie importuje obiektów z prefiksem podkreślenia. Dlatego_foo
jest czymś więcej niż tylko konwencją.B
klasęA
i obie implementująfoo()
, toB.foo()
zastępuje.foo()
odziedziczoneA
.B
Dostęp do instancji będzie możliwy tylko zaB.foo()
pośrednictwemsuper(B).foo()
.__dunder__
nazw niejawne wywołania pomijają słownik instancji, więc w niektórych przypadkach może to być coś więcej niż tylko konwencja nazewnictwa (patrz sekcja poświęcona specjalnej metodzie wyszukiwania w modelu danych).._variable
jest półprywatny i przeznaczony tylko do konwencji.__variable
jest często błędnie uważany za superprywatny, a jego faktyczne znaczenie to po prostu namemangle, aby zapobiec przypadkowemu dostępowi [1].__variable__
jest zwykle zarezerwowany dla wbudowanych metod lub zmiennychNadal możesz uzyskać dostęp do
.__mangled
zmiennych, jeśli desperacko chcesz. Podwójne podkreślenia po prostu namemangles lub zmienia nazwę zmiennej na coś podobnegoinstance._className__mangled
Przykład:
t._b jest dostępny, ponieważ jest ukryty tylko przez konwencję
t .__ a nie został znaleziony, ponieważ już nie istnieje z powodu namemangling
Uzyskując dostęp
instance._className__variable
zamiast podwójnej nazwy podkreślenia, można uzyskać dostęp do ukrytej wartościźródło
Pojedynczy podkreślnik na początku:
Python nie ma prawdziwych prywatnych metod. Zamiast tego jeden znak podkreślenia na początku nazwy metody lub atrybutu oznacza, że nie powinieneś uzyskiwać dostępu do tej metody, ponieważ nie jest ona częścią interfejsu API.
(Ten fragment kodu został pobrany z kodu źródłowego django: django / form / forms.py). W tym kodzie
errors
jest własnością publiczną, ale metoda wywoływana przez tę właściwość _get_errors jest „prywatna”, więc nie powinieneś mieć do niej dostępu.Na początek dwa podkreślenia:
Powoduje to wiele zamieszania. Nie należy go używać do tworzenia prywatnej metody. Należy go użyć, aby uniknąć zastąpienia metody przez podklasę lub przypadkowego dostępu do niej. Zobaczmy przykład:
Wynik:
Teraz utwórz podklasę B i dostosuj metodę __test
Wyjście będzie ....
Jak widzieliśmy, A.test () nie wywołał metod B .__ test (), jak można się spodziewać. Ale w rzeczywistości jest to prawidłowe zachowanie dla __. Dwie metody o nazwie __test () są automatycznie przemianowane (zniekształcone) na _A__test () i _B__test (), aby przypadkowo nie zostały zastąpione. Kiedy tworzysz metodę zaczynającą się od __, oznacza to, że nie chcesz, aby ktokolwiek mógł ją zastąpić, i masz zamiar uzyskać do niej dostęp tylko z jej własnej klasy.
Dwa podkreślenia na początku i na końcu:
Kiedy widzimy metodę podobną
__this__
, nie nazywaj jej. Jest to metoda, którą ma wywoływać Python, a nie ty. Spójrzmy:Zawsze istnieje operator lub natywna funkcja, która wywołuje te magiczne metody. Czasami jest to zwykłe wywołanie Pythona w określonych sytuacjach. Na przykład
__init__()
jest wywoływany, gdy obiekt jest tworzony po__new__()
wywołaniu w celu utworzenia instancji ...Weźmy przykład ...
Aby uzyskać więcej informacji, zobacz przewodnik PEP-8 . Więcej magicznych metod znajdziesz w tym pliku PDF .
źródło
Czasami masz coś, co wydaje się być krotką z wiodącym podkreśleniem, jak w
W tym przypadku chodzi o to, że _ () jest aliasem dla funkcji lokalizacji, która działa na tekście, aby umieścić go we właściwym języku itp. W zależności od ustawień regionalnych. Na przykład Sphinx to robi, a znajdziesz wśród importowanych
a w sphinx.locale, _ () jest przypisany jako alias niektórych funkcji lokalizacji.
źródło
Ponieważ tak wiele osób odnosi się do przemówienia Raymonda, ułatwię to , pisząc to, co powiedział:
Załóżmy, że nie prowadzą lokalne odniesienie
perimeter
wCircle
. Teraz klasa pochodnaTire
zastępuje implementacjęperimeter
bez dotykaniaarea
. Kiedy dzwoniszTire(5).area()
, teoretycznie powinien on nadal być wykorzystywanyCircle.perimeter
do obliczeń, ale w rzeczywistości używaTire.perimeter
, co nie jest zamierzonym zachowaniem. Dlatego potrzebujemy lokalnego odniesienia w Circle.Ale dlaczego
__perimeter
zamiast_perimeter
? Ponieważ_perimeter
wciąż daje klasie pochodnej szansę na przesłonięcie:Podwójne podkreślenia mają mangowanie nazw, więc istnieje małe prawdopodobieństwo, że lokalne odwołanie w klasie nadrzędnej zostanie zastąpione w klasie pochodnej. w ten sposób „ sprawia, że Twoje podklasy mogą zastąpić jedną metodę, nie psując pozostałych ”.
Jeśli twoja klasa nie zostanie odziedziczona lub zastąpienie metody niczego nie zepsuje, po prostu nie potrzebujesz
__double_leading_underscore
.źródło
Jeśli naprawdę chcemy, aby zmienna była tylko do odczytu, IMHO najlepiej byłoby użyć property () z przekazanym tylko getterowi. Dzięki property () możemy mieć pełną kontrolę nad danymi.
Rozumiem, że OP zadał nieco inne pytanie, ale ponieważ znalazłem inne pytanie z pytaniem „jak ustawić zmienne prywatne” oznaczone jako duplikat tego, pomyślałem o dodaniu tutaj tych dodatkowych informacji.
źródło
Zgadzając się z https://dbader.org/blog/meaning-of-underscores-in-python
źródło
Świetne odpowiedzi i wszystkie są poprawne. Podałem prosty przykład wraz z prostą definicją / znaczeniem.
Znaczenie:
some_variable --► jest publiczny, każdy może to zobaczyć.
_some_variable --► jest publiczny, każdy może to zobaczyć, ale jest to konwencja oznaczająca prywatność ... ostrzegająca, że Python nie wymusza żadnego egzekwowania.
__some_varaible --► Python zamienia nazwę zmiennej na _classname__some_varaible (zniekształcanie nazwy AKA) i zmniejsza / ukrywa widoczność i przypomina bardziej zmienną prywatną.
Mówiąc szczerze, zgodnie z dokumentacją Pythona
Przykład:
źródło
Pojedyncze wiodące podkreślenia to konwencja. z punktu widzenia tłumacza nie ma różnicy, czy nazwy zaczynają się od pojedynczego podkreślenia, czy nie.
Podwójne natarcia i spływu podkreślenia służą do wbudowanej metodami, takimi jak
__init__
,__bool__
itpPodwójne wiodące podkreślenia bez końcowych odpowiedników są również konwencją, jednak metody klasowe zostaną zniekształcone przez interpretera. W przypadku zmiennych lub podstawowych nazw funkcji nie ma żadnej różnicy.
źródło
Twoje pytanie jest dobre, nie dotyczy tylko metod. Funkcje i obiekty w modułach są często poprzedzone jednym znakiem podkreślenia i mogą być poprzedzone dwoma.
Ale nazwy __double_underscore nie są na przykład zniekształcone w modułach. To, co się dzieje, polega na tym, że nazwy rozpoczynające się od jednego (lub więcej) podkreślników nie są importowane, jeśli importujesz wszystko z modułu (z importu modułu *), a także nazwy wyświetlane w pomocy (module).
źródło
Oto prosty przykład ilustrujący, w jaki sposób właściwości podwójnego podkreślenia mogą wpływać na odziedziczoną klasę. Więc z następującą konfiguracją:
jeśli następnie utworzysz instancję potomną w REPL pytona, zobaczysz poniżej
Dla niektórych może to być oczywiste, ale zaskoczyło mnie to w znacznie bardziej złożonym środowisku
źródło
„Prywatne” zmienne instancji, do których nie można uzyskać dostępu, chyba że z wnętrza obiektu, nie istnieją w Pythonie. Istnieje jednak konwencja, po której następuje większość kodu w języku Python: nazwa poprzedzona znakiem podkreślenia (np. _Spam) powinna być traktowana jako niepubliczna część interfejsu API (niezależnie od tego, czy jest to funkcja, metoda czy element danych) . Należy to uznać za szczegół implementacji i może ulec zmianie bez powiadomienia.
odniesienie https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
źródło
Poznanie faktów _ i __ jest dość łatwe; inne odpowiedzi wyrażają je całkiem dobrze. Użycie jest znacznie trudniejsze do ustalenia.
Tak to widzę:
Powinien być używany do wskazania, że funkcja nie jest do użytku publicznego, jak na przykład interfejs API. To i ograniczenie importu sprawiają, że zachowuje się podobnie jak
internal
w języku c #.Powinien być używany, aby uniknąć kolizji nazw w hierarchii dziedziczenia i aby uniknąć późnego wiązania. Podobnie jak prywatny w c #.
==>
Jeśli chcesz wskazać, że coś nie jest do użytku publicznego, ale powinno działać jak
protected
pożytek_
. Jeśli chcesz wskazać, że coś nie jest do użytku publicznego, ale powinno działać jakprivate
pożytek__
.Jest to również cytat, który bardzo lubię:
Moim zdaniem problem polega na tym, że jeśli nie ma IDE, który ostrzegałby Cię podczas nadpisywania metod, znalezienie błędu może zająć trochę czasu, jeśli przypadkowo zastąpisz metodę z klasy podstawowej.
źródło