Koje je značenje jednostruke i dvostruke donje crte ispred imena objekta?

Može li netko objasniti što je točno podcrtana vrijednost ispred naziva objekta u Pythonu? Također objasnite razliku između jednostrukih i dvostrukih vodećih podvlake. Isto tako, ima li ista stvar smisla, je li predmet u pitanju varijabla, funkcija, metoda, itd.?

1055
19 авг. Ram Rachum je pitao 19. kolovoza . 2009-08-19 20:11 '09 u 20:11 2009-08-19 20:11
@ 15 odgovora

Jedna poddlaka

Imena u klasi s vodećom donjom crtom jednostavno ukazuju drugim programerima da je atribut ili metoda namijenjena privatnosti. Međutim, ništa posebno se ne radi s samim imenom.

Za citiranje PEP-8 :

_single_leading_underscore: slab indikator "interne upotrebe". Na primjer, from M import * ne uvozi objekt čije ime počinje s podcrtavanjem.

Dvostruka donja crta (naziv Mangling)

Iz Python dokumenata :

Bilo koji identifikator obrasca __spam (najmanje dva vodeća __spam , ne više od jedne donje crte) zamjenjuje se _classname__spam , gdje je classname trenutno ime klase s _classname__spam podcrtavanjem. Ta se manipulacija provodi bez obzira na sintaktičku poziciju identifikatora, pa se može koristiti za definiranje varijabli klase, varijabli klasa pohranjenih u globalnim varijablama, pa čak i varijabli pohranjenih u instancama. privatni za ovu klasu na primjercima drugih klasa.

I upozorenje s iste stranice:

Namjena imena je dati klasama jednostavan način definiranja "privatnih" varijabli i metoda instance, ne brinući se o varijablama instance koje definiraju izvedene klase, ili varati varijable instance s kodom izvan klase. Imajte na umu da su pravila manipulacije prvenstveno namijenjena sprječavanju nesreća; još uvijek je moguće da određena duša pristupi ili promijeni varijablu koja se smatra privatnom.

primjer

 >>> 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!'} 
964
19 авг. Odgovor je dao Andrew Keeton 19. kolovoza. 2009-08-19 20:15 '09 u 20:15 2009-08-19 20:15

Odlični odgovori do sada, ali neke sitnice nedostaju. Jedina vodeća donja crta nije samo konvencija: ako koristite from foobar import * , a foobar modul ne definira popis __all__ , imena uvezena iz modula ne uključuju one s vodećom donjom __all__ . Recimo da je to u osnovi konvencija, budući da je ovaj slučaj prilično nejasan kut; -).

Konvencija donje crte široko se koristi ne samo za privatna imena, već i za ono što su C ++ pozivi zaštićeni - na primjer, imena metoda koja su u potpunosti namijenjena da budu redefinirana podklasama (čak i onima koji postoje , jer u osnovnoj klasi raise NotImplementedError ! - ) često su imena s jednom vodećom donjom crtom koja upućuje na kod pomoću primjeraka ove klase (ili podklasa), koje navedene metode ne bi trebalo izravno pozivati.

border=0

Na primjer, za stvaranje niza sigurnog reda s drugom disciplinom reda nego FIFO, jedan uvozi red čekanja, potklase Queue.Queue i nadjačava metode kao što su _get i _put ; "Kôd klijenta" ne zove te metode ("kuka"), nego ("organiziranje") javnih metoda, kao što je put i get (to se zove Metoda predloška - pogledajte, primjerice, ovdje za zanimljivu prezentaciju na temelju videa mog razgovora o uz ovaj kratki prijepis).

276
19 авг. odgovor dao Alex Martelli 19 aug. 2009-08-19 20:52 '09 u 20:52 2009-08-19 20:52

__foo__ : ovo je samo konvencija, način za korištenje Python sustava za nazive koji nisu u sukobu s korisničkim imenima.

_foo : ovo je samo konvencija, način na koji programer može naznačiti da je varijabla privatna (što god da je u Pythonu).

__foo : ima pravo značenje: tumač zamjenjuje ovaj naziv _classname__foo kao način da se osigura da se ime ne preklapa sa sličnim imenom u drugom razredu.

Nijedna druga naglašavanja nema smisla u Python svijetu.

U tim konvencijama nema razlike između klasa, varijabla, globalnog itd.

262
19 авг. Odgovor je dao Ned Batchelder 19. kolovoza. 2009-08-19 20:21 '09 u 20:21 2009-08-19 20:21

._variable je polu-privatna i namijenjena je samo sporazumu

.__variable često pogrešno smatra super-profitom, dok je stvarna vrijednost jednostavno spriječiti namemangle od slučajnog pristupa [1]

.__variable__ obično rezervirana za ugrađene metode ili varijable.

Možete pristupiti .__mangled varijablama .__mangled ako to očajnički želite. Dvostruka donja crta je jednostavno imenovati ili preimenovati varijablu u nešto poput instance._className__mangled

primjer:

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

t._b je dostupan jer je skriven samo sporazumom.

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

t .__ a nije pronađen jer više ne postoji zbog nametanja

 >>> t._Test__a 'a' 

Pristupanjem instance._className__variable umjesto imena dvostruke podvlake, možete pristupiti skrivenoj vrijednosti.

184
27 сент. Odgovor je dan NickCSE 27 sep . 2012-09-27 23:56 '12 u 23:56 2012-09-27 23:56

Jedina donja crta na početku:

Python nema pravih privatnih metoda. Umjesto toga, jedna donja crta na početku naziva metode ili atributa znači da ne biste trebali pristupiti ovoj metodi jer ona nije dio API-ja.

 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) 

(Ovaj isječak koda preuzet je iz izvornog koda django: django / forms / forms.py). U ovom su kodu errors javne, ali metoda koju ova metoda poziva, _get_errors, je "privatna", tako da joj ne biste trebali pristupiti.

Dvije podvlake na početku:

To uzrokuje veliku konfuziju. Ne može se koristiti za stvaranje privatne metode. Trebao bi se koristiti kako bi se izbjeglo poništavanje vaše metode potklasiranjem ili slučajnim pristupom. Razmotrite primjer:

 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! 

izlaz:

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

Sada kreirajte podklasu B i prilagodite metodu __test

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

Izlaz će biti ...

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

Kao što smo vidjeli, A.test () nije nazvao B .__ test () metode, kao što se očekivalo. Ali zapravo je to ispravno ponašanje za __. Dvije metode, nazvane __test (), automatski se preimenuju (izobličene) u _A__test () i _B__test (), tako da ne slučajno pregaze. Kada stvorite metodu koja počinje s __, to znači da ne želite da je itko nadjačava, a vi samo namjeravate pristupiti iz vlastite klase.

Dvije podvlake na početku i kraju:

Kada vidimo metodu kao __this__ , nemojte je zvati. To je metoda koju je Python trebao nazvati, a ne za vas. Dopustite mi da pogledam:

 >>> name = "test string" >>> name.__len__() 11 >>> len(name) 11 >>> number = 10 >>> number.__add__(40) 50 >>> number + 50 60 

Uvijek postoji operator ili izvorna funkcija koja poziva te magične metode. Ponekad je to samo poziv u određenim situacijama. Na primjer, __init__() se poziva kada je objekt stvoren nakon __new__() za stvaranje instance ...

Uzmite primjer ...

 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 

Za više informacija pogledajte PEP-8 vodič . Za dodatne magijske metode, pogledajte ovu pdf datoteku .

94
15 дек. Odgovor je dat PythonDev 15 prosinca. 2014-12-15 13:10 '14 u 13:10 2014-12-15 13:10

Ponekad imate ono što izgleda kao torka s vodećom donjom crtom, kao u

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

U ovom slučaju, ono što se događa jest da je _ () pseudonim za funkciju lokalizacije koja radi s tekstom da bi ga stavila na ispravan jezik itd. na temelju regionalne postavke. Na primjer, Sphinx to radi i naći ćete se među uvozom

 from sphinx.locale import l_, _ 

i u sphinx.locale, _ () je dodijeljen kao pseudonim za neke funkcije lokalizacije.

15
11 янв. Odgovor je dao Tim D 11. siječnja. 2012-01-11 19:28 '12 u 19:28 2012-01-11 19:28

Podcrtano (_) u Pythonu

Ovo su različita mjesta gdje se _ koristi u Pythonu:

Pojedinačna donja crta:

  • U prevoditelju
  • Nakon imena
  • Prije imena

Dvostruka donja crta:

  • __leading_double_underscore

  • prije poslije

  • Jedna poddlaka

U prevoditelju:

_ vraća vrijednost zadnje izvršene vrijednosti izraza u 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 

Za zanemarivanje vrijednosti:

Nekoliko puta ne želimo da vraćene vrijednosti u ovom trenutku dodijele ove vrijednosti wnderscoreu. Koristi se kao varijabla.

 # Ignore a value of specific location/index for _ in rang(10) print "Test" # Ignore a value when unpacking a,b,_,_ = my_method(var1) 

Nakon imena

Python ima svoje zadane ključne riječi koje ne možemo koristiti kao ime varijable. Da bismo izbjegli takav sukob između ključnih riječi i varijable python, nakon naziva koristimo donju crtu

primjer:

 >>> class MyClass(): ... def __init__(self): ... print "OWK" >>> def my_defination(var1 = 1, class_ = MyClass): ... print var1 ... print class_ >>> my_defination() 1 __main__.MyClass >>> 

Prije imena

Vodeće podcrtavanje ispred imena varijable / funkcije / metode ukazuje programeru da je namijenjeno samo internoj upotrebi, koja se može mijenjati svaki put kada se zahtijeva klasa.

Ovdje se prefiks podcrtanjem smatra nejavnim. Ako navedete iz Uvezi *, cijelo ime počinje s _ neće biti uvezeno.

Python zapravo ne ukazuje na privatnost, tako da se može pozvati izravno s drugih modula, ako su navedeni u svim , također ga zovemo slabo Privatno

 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" 

Pozivanje datoteke iz REPL-a

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

Vodeći dvostruki znak podcrtava python interpretera da prepiše ime kako bi se izbjeglo sukob u potklasi. Interpreter mijenja ime varijable s nastavkom klase i ovom funkcijom, poznatom kao Mangling. testFile.py

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

Nazovite 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 

U Python Mangling interpretatoru promijenite ime varijable na ___. Dakle, množina se koristi kao privatni član, jer druga klasa ne može izravno pristupiti ovoj varijabli. Glavna svrha __ je koristiti varijablu / metodu samo u klasi. Ako ga želite koristiti izvan razreda, možete napraviti javni api

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

Nazovite REPL

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

__DAY AFTER__

Ime počinje s __ i završava istim posebnim metodama u Pythonu. Python nudi ove metode za korištenje kao preopterećenje operatora ovisno o korisniku.

Python pruža ovu konvenciju za razlikovanje korisnički definirane funkcije pomoću modula

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

Nazovite REPL

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

veza

10
25 янв. odgovor je dao Chirag Maliwal na 25. siječnja. 2018-01-25 16:47 '18 u 4:47 2018-01-25 16:47

Ako doista želite napraviti varijablu samo za čitanje, IMHO najbolji način bio bi da koristite svojstvo () sa samo da ga dobije. S svojstvom () možemo imati potpunu kontrolu nad podacima.

 class PrivateVarC(object): def get_x(self): pass def set_x(self, val): pass rwvar = property(get_p, set_p) ronly = property(get_p) 

Razumijem da je OP postavilo nešto drugačije pitanje, ali kako sam pronašla drugo pitanje s pitanjem kako označiti označene duplikate za pojedine varijable, razmišljala sam o dodavanju dodatnih informacija ovdje.

7
15 апр. Odgovor dao Dev Maha 15. travnja 2013-04-15 04:58 '13 u 4:58 2013-04-15 04:58

Pojedinačne podvlake su konvencija. nema razlike u odnosu na točku tumača ako imena počinju s jednom donjom crtom ili ne.

Dvostruke vodeće i završne donje crte koriste se za ugrađene metode kao što su __init__ , __bool__ , itd.

Dvostruko vodeće podvlačenje bez pratećih analoga također je sporazum, međutim, metode klasa će biti izobličene od strane tumača. Za varijable ili osnovna imena funkcija, razlika ne postoji.

5
19 авг. odgovor je dan SilentGhost 19 aug. 2009-08-19 20:17 '09 u 20:17 2009-08-19 20:17

Evo jednostavnog ilustrativnog primjera kako svojstva dvostruke donje crte mogu utjecati na naslijeđenu klasu. Dakle, sa sljedećom postavkom:

 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" 

ako zatim stvorite podređenu instancu u python REPL-u, vidjet ćete u nastavku

 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' 

Ovo može biti očito za neke, ali me je našlo na sigurnom u mnogo složenijem okruženju.

3
22 авг. Odgovor je dan Marc 22 aug. 2014-08-22 22:15 '14 u 22:15 sati 2014-08-22 22:15

"Privatne" varijable instance kojima se ne može pristupiti, osim unutar objekta, ne postoje u Pythonu. Međutim, postoji dogovor koji slijedi većina Python koda: ime s prefiksom podvlake (na primjer, _spam) treba smatrati nejavnim dijelom API-ja (bilo da je riječ o funkciji, metodi ili elementu podataka). bez obavijesti.

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

3
07 февр. odgovor je dao aptro 07 Feb. 2015-02-07 20:57 '15 u 20:57 2015-02-07 20:57

Vaše je pitanje dobro, ne radi se samo o metodama. Funkcije i objekti u modulima obično imaju prefiks s jednom donjom crtom i mogu biti prefiks s dva.

Ali imena __double_underscore, na primjer, ne obrađuju se imenima u modulima. Događa se da se imena koja počinju s jednom (ili više) donjih crta ne uvoze ako uvezete sve iz modula (iz uvoza modula *), kao i imena navedena u pomoći (modulu).

3
19 авг. odgovor je dat u0b34a0f6ae 19. kolovoza . 2009-08-19 20:31 '09 u 20:31 2009-08-19 20:31

Dobivanje činjenica _ i __ je prilično jednostavno; drugi odgovori dobro ih izražavaju. Mnogo je teže odrediti uporabu.

Evo kako to vidim:

 _ 

Koristi se za označavanje da funkcija nije namijenjena za javnu upotrebu, kao što je API. Ova i uvozna ograničenja čine da izgleda kao internal na C #.

 __ 

Trebao bi se koristiti kako bi se izbjegli sukobi imena u nasljedstvu hirarhije i izbjeglo kasno obvezivanje. Vrlo sličan C #.

==>

Ako želite naznačiti da nešto nije za opću upotrebu, ali bi trebalo djelovati kao protected korištenje _ . Ako želite naznačiti da nešto nije za opću upotrebu, ali bi trebalo djelovati kao private upotreba __ .

Ovo je također citat koji mi se stvarno sviđa:

Problem je u tome što autor klase može legitimno misliti da "ime ovog atributa / metode mora biti privatno, dostupno samo iz ove definicije klase" i koristiti konvenciju __private, ali kasnije, korisnik ove klase može napraviti potklasu koja legitimno treba pristup ovom imenu. , Dakle, bilo bi potrebno promijeniti nadrazred (što može biti teško ili nemoguće), ili kod podrazreda treba koristiti ručno iskrivljena imena (koja su u najboljem slučaju ružna i krhka).

Ali problem s ovim po mom mišljenju je da ako ne postoji IDE koji vas upozorava kada pregazite metode, potraga za pogreškom može potrajati neko vrijeme ako slučajno završite metodu iz osnovne klase.

0
04 нояб. odgovor je dat Ini 04 Nov. 2017-11-04 20:46 '17 u 8:46 2017-11-04 20:46

Izvrsni odgovori i svi su ispravni. Dao sam jednostavan primjer uz jednostavnu definiciju / vrijednost.

Imajući na umu:

some_variable --► to je javno svatko može vidjeti.

_some_variable --► ovo je javno, svatko ga može vidjeti, ali ovaj sporazum određuje posebno ... upozorenje da Python ne poduzima nikakve mjere.

__some_varaible --► Python zamjenjuje ime varijable s _classname__some_varaible (izobličenje imena AKA) i smanjuje / skriva svoju vidljivost i više je kao privatna varijabla.

Samo da budem iskren, prema Python dokumentaciji.

"Privatne" varijable instance kojima se ne može pristupiti, osim unutar objekta koji nije u Pythonu "

primjer:

 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 not public variable #print(aObject.__here) 
0
22 янв. odgovor je dan grepit 22. siječnja 2019-01-22 01:23 '19 u 1:23 am 2019-01-22 01:23

Budući da mnogi misle da Raymond govori , samo ću malo olakšati pisanjem onoga što je rekao:

Namjera dvostrukog podcrtavanja nije bila privatnost. Namjera je bila iskoristiti točno onakve kakve jesu

 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 

To je zapravo suprotno od privatnog života, sve je u slobodi. To čini vaše podklase slobodnim da zaobiđu bilo koju metodu bez ometanja drugih .

Recimo da ne spremate lokalnu vezu na perimeter u Circle . Sada izvedena klasa Tire nadjačava provedbu perimeter bez dodirivanja area . Kada pozovete Tire(5).area() , teoretski bi i dalje trebalo koristiti Circle.perimeter za izračune, ali u stvarnosti koristi Tire.perimeter , što nije namjerno ponašanje. Zato trebamo lokalnu vezu u krugu.

Ali zašto __perimeter umjesto _perimeter ? Jer _perimeter dalje daje izvedenoj klasi mogućnost poništavanja:

 class Tire(Circle): def perimeter(self): return Circle.perimeter(self) * 1.25 _perimeter = perimeter 

Dvostruka donja crta ima izobličenje imena, tako da postoji mala vjerojatnost da će lokalna referenca u roditeljskoj klasi dobiti nadjačavanje u izvedenoj klasi. tako " čini vaše podklase slobodnim redefinirati bilo koju metodu, bez ometanja drugih ."

Ako vaš razred nije naslijeđen ili poništavanje metode ne krši ništa, jednostavno vam ne treba __double_leading_underscore .

0
20 окт. odgovor od laike9m 20. listopada 2018-10-20 11:10 '18 u 11:10 sati 2018-10-20 11:10