Pochodzę ze świata Java i czytam Bruce'a Eckelsa Wzory, przepisy i idiomy języku Python 3 .
Podczas czytania o klasach mówi się dalej, że w Pythonie nie ma potrzeby deklarowania zmiennych instancji. Po prostu używasz ich w konstruktorze i bum, są tam.
Na przykład:
class Simple:
def __init__(self, s):
print("inside the simple constructor")
self.s = s
def show(self):
print(self.s)
def showMsg(self, msg):
print(msg + ':', self.show())
Jeśli to prawda, to każdy obiekt klasy Simple
może po prostu zmienić wartość zmiennejs
poza klasą.
Na przykład:
if __name__ == "__main__":
x = Simple("constructor argument")
x.s = "test15" # this changes the value
x.show()
x.showMsg("A message")
W Javie uczono nas o zmiennych publicznych / prywatnych / chronionych. Te słowa kluczowe mają sens, ponieważ czasami chcesz zmiennych w klasie, do których nikt poza klasą nie ma dostępu.
Dlaczego nie jest to wymagane w Pythonie?
Odpowiedzi:
To kulturalne. W Pythonie nie piszesz do instancji lub zmiennych klas innych klas. W Javie nic nie stoi na przeszkodzie, abyś zrobił to samo, jeśli naprawdę tego chcesz - w końcu zawsze możesz edytować źródło samej klasy, aby osiągnąć ten sam efekt. Python porzuca pozory bezpieczeństwa i zachęca programistów do odpowiedzialności. W praktyce działa to bardzo dobrze.
Jeśli z jakiegoś powodu chcesz emulować zmienne prywatne, zawsze możesz użyć
__
prefiksu z PEP 8 . Python Zmieniany nazwy zmiennych podoba__foo
tak, że nie są łatwo widoczne dla kodu poza klasą, który zawiera je (choć można ominąć, jeśli jesteś zdecydowany na tyle, tak jak puszka obejść zabezpieczenia Java, jeśli pracujesz na nim ).Zgodnie z tą samą konwencją
_
prefiks oznacza trzymanie się z dala, nawet jeśli nie jest to technicznie niemożliwe . Nie bawisz się zmiennymi innej klasy, które wyglądają jak__foo
lub_bar
.źródło
Prywatne zmienne w pythonie są mniej więcej włamaniem: interpreter celowo zmienia nazwę zmiennej.
Teraz, jeśli spróbujesz uzyskać dostęp
__var
poza definicją klasy, zakończy się ona niepowodzeniem:Ale możesz łatwo uciec od tego:
Prawdopodobnie wiesz, że metody w OOP są wywoływane w następujący sposób:
x.printVar() => A.printVar(x)
jeśliA.printVar()
można uzyskać dostęp do jakiegoś pola wewnątrzx
, do tego pola można również uzyskać dostęp na zewnątrzA.printVar()
... w końcu funkcje są tworzone w celu ponownego użycia, nie ma żadnej szczególnej mocy dla instrukcji wewnątrz.Gra różni się, gdy w grę wchodzi kompilator ( prywatność to koncepcja na poziomie kompilatora ). Wie o definicji klasy z modyfikatorami kontroli dostępu, więc może popełnić błąd, jeśli reguły nie będą przestrzegane w czasie kompilacji
źródło
Jak słusznie wspomniano w wielu powyższych komentarzach, nie zapominajmy o głównym celu Modyfikatorów dostępu: Pomaganiu użytkownikom kodu zrozumieć, co powinno się zmienić, a co nie. Kiedy zobaczysz prywatne pole, nie będziesz się z nim bawić. Więc jest to głównie cukier składniowy, który jest łatwo osiągalny w Pythonie przez _ i __.
źródło
Istnieje konwencja zmiennych prywatnych w konwencji podkreślenia.
Istnieją pewne subtelne różnice, ale ze względu na programowanie wzoru ideologiczna czystość jest wystarczająca.
Istnieją przykłady dekoratorów @private, które ściślej wdrażają tę koncepcję, ale YMMV. Prawdopodobnie można również napisać definicję klasy, która używa meta
źródło
__x
jako zmienna wewnątrz klasyA
kompilator przepisał_A__x
, nadal nie jest ona w pełni prywatna i nadal można uzyskać do niej dostęp._A__x
, nie zamierzam jej dotykać. To może być zaraźliwe. Ucieknę od tego.„W Javie uczono nas o zmiennych publicznych / prywatnych / chronionych”
„Dlaczego nie jest to wymagane w Pythonie?”
Z tego samego powodu nie jest to wymagane w Javie.
Możesz swobodnie korzystać - lub nie używać
private
iprotected
.Jako programista Python i Java znalazłem to
private
iprotected
są to bardzo, bardzo ważne koncepcje projektowe. Ale w praktyce, w dziesiątkach tysięcy linii Java i Pythona, tak naprawdę nigdy nie korzystałem zprivate
aniprotected
.Dlaczego nie?
Oto moje pytanie „chroniony przed kim?”
Inni programiści w moim zespole? Mają źródło. Co oznacza ochrona, kiedy mogą to zmienić?
Inni programiści z innych zespołów? Pracują dla tej samej firmy. Mogą - podczas rozmowy telefonicznej - uzyskać źródło.
Klienci? Jest to program do pracy najemnej (ogólnie). Klienci (ogólnie) są właścicielami kodu.
Więc przed kim dokładnie go chronię?
źródło
Jak wspomniano wcześniej, można wskazać, że zmienna lub metoda jest prywatna, poprzedzając ją znakiem podkreślenia. Jeśli nie uważasz, że to wystarczy, zawsze możesz użyć
property
dekoratora. Oto przykład:W ten sposób ktoś lub coś, do czego się odwołuje,
bar
faktycznie odwołuje się do wartości zwracanej przezbar
funkcję, a nie do samej zmiennej, a zatem można uzyskać do niej dostęp, ale nie można jej zmienić. Jednak jeśli ktoś naprawdę tego chce, może po prostu użyć_bar
i przypisać mu nową wartość. Nie ma pewnego sposobu, aby uniemożliwić komuś dostęp do zmiennych i metod, które chcesz ukryć, jak wielokrotnie powtarzano. Jednak użycieproperty
jest najczystszym komunikatem, który można wysłać, że zmiennej nie można edytować.property
może być również używany do bardziej złożonych ścieżek dostępu do getter / setter / deleter, jak wyjaśniono tutaj: https://docs.python.org/3/library/functions.html#propertyźródło
Python ma ograniczoną obsługę prywatnych identyfikatorów, dzięki funkcji, która automatycznie dołącza nazwę klasy do dowolnych identyfikatorów rozpoczynających się od dwóch znaków podkreślenia. Jest to przeważnie przezroczyste dla programisty, ale efektem netto jest to, że dowolne zmienne nazwane w ten sposób mogą być używane jako zmienne prywatne.
Zobacz tutaj więcej na ten temat.
Ogólnie rzecz biorąc, implementacja orientacji obiektowej w Pythonie jest nieco prymitywna w porównaniu do innych języków. Ale tak naprawdę to lubię. Jest to bardzo koncepcyjnie prosta implementacja i dobrze pasuje do dynamicznego stylu języka.
źródło
Jedynym razem, kiedy korzystam ze zmiennych prywatnych, jest to, że muszę robić inne rzeczy podczas pisania lub odczytywania zmiennych i jako takie muszę wymusić użycie settera i / lub gettera.
Ponownie dotyczy to kultury, jak już wspomniano. Pracowałem nad projektami, w których czytanie i pisanie zmiennych innych klas było bezpłatne dla wszystkich. Kiedy jedna implementacja stała się przestarzała, identyfikacja wszystkich ścieżek kodu, które korzystały z tej funkcji, zajęła dużo więcej czasu. Gdy wymuszono użycie zestawów ustawiających i pobierających, można łatwo napisać instrukcję debugowania, aby zidentyfikować, że wywołano przestarzałą metodę i ścieżkę kodu, która ją wywołuje.
Kiedy pracujesz nad projektem, w którym każdy może napisać rozszerzenie, powiadamianie użytkowników o przestarzałych metodach, które mają zniknąć w kilku wydaniach, dlatego bardzo ważne jest, aby ograniczyć awarie modułów do minimum podczas aktualizacji.
Więc moja odpowiedź brzmi; jeśli ty i twoi koledzy macie prosty zestaw kodów, ochrona zmiennych klas nie zawsze jest konieczna. Jeśli piszesz system rozszerzalny, staje się konieczny, gdy wprowadzane są zmiany w rdzeniu, które muszą zostać przechwycone przez wszystkie rozszerzenia korzystające z kodu.
źródło
Prywatne i chronione pojęcia są bardzo ważne. Ale python - tylko narzędzie do prototypowania i szybkiego rozwoju z ograniczonymi zasobami dostępnymi do programowania, dlatego niektóre poziomy ochrony nie są tak rygorystyczne w Pythonie. Możesz użyć „__” w klasie, działa poprawnie, ale nie wygląda wystarczająco dobrze - każdy dostęp do takiego pola zawiera te znaki.
Można również zauważyć, że koncepcja OOP w Pythonie nie jest idealna, smaltalk lub rubin jest znacznie bliższa czystej koncepcji OOP. Nawet C # lub Java są bliżej.
Python jest bardzo dobrym narzędziem. Ale jest to uproszczony język OOP. Uproszczone pod względem składniowym i koncepcyjnym. Głównym celem istnienia Pythona jest zapewnienie programistom możliwości szybkiego pisania czytelnego kodu o wysokim poziomie abstrakcji.
źródło
Przepraszam chłopaki za „wskrzeszenie” wątku, ale mam nadzieję, że to pomoże komuś:
W Python3, jeśli chcesz po prostu „obudować” atrybuty klasy, tak jak w Javie, możesz po prostu zrobić to samo:
Aby utworzyć instancję, wykonaj następujące czynności:
Uwaga:
print(ss.__s)
wyrzuci błąd.W praktyce Python3 zaciemni globalną nazwę atrybutu. Zmieniając to na „prywatny” atrybut, jak w Javie. Nazwa atrybutu jest nadal globalna, ale niedostępna, podobnie jak atrybut prywatny w innych językach.
Ale nie bój się tego. To nie ma znaczenia To też działa. ;)
źródło
Python nie ma żadnych prywatnych zmiennych, takich jak C ++ lub Java. W razie potrzeby można uzyskać dostęp do dowolnej zmiennej składowej w dowolnym momencie. Jednak nie potrzebujesz prywatnych zmiennych w Pythonie, ponieważ w Pythonie nie jest źle eksponować zmienne składowe klas. Jeśli potrzebujesz enkapsulować zmienną składową, możesz to zrobić, używając później „@property” bez zerwania istniejącego kodu klienta.
W pythonie pojedynczy znak podkreślenia „_” służy do wskazania, że metoda lub zmienna nie jest uważana za część publicznego interfejsu API klasy i że ta część interfejsu API może zmieniać się między różnymi wersjami. Możesz użyć tych metod / zmiennych, ale kod może się zepsuć, jeśli użyjesz nowszej wersji tej klasy.
Podwójny znak podkreślenia „__” nie oznacza „zmiennej prywatnej”. Używasz go do definiowania zmiennych, które są „klasami lokalnymi” i których nie można łatwo ominąć podklasami. Zmienia nazwę zmiennej.
Na przykład:
self .__ nazwa foobar jest automatycznie zniekształcana do self._A__foobar w klasie A. W klasie B jest przekształcana w self._B__foobar. Każda podklasa może więc zdefiniować własną zmienną __foobar bez nadpisywania zmiennych nadrzędnych. Ale nic nie stoi na przeszkodzie, aby uzyskać dostęp do zmiennych zaczynających się od podwójnych znaków podkreślenia. Jednak zmiana nazwy uniemożliwia przypadkowe wywołanie tych zmiennych / metod.
Zdecydowanie polecam oglądać Raymonda Hettingersa rozmawiającego na temat „zestawu narzędzi rozwojowych klasy Python” z Pycon 2013 (powinien być dostępny na Youtube), który daje dobry przykład, dlaczego i jak należy używać @property i „__” - zmiennych instancji.
źródło
@property
rzecz jest częścią standardowego Pythona, czy jest specyficzna dla IDE?property
wbudowanej funkcji, która jest dostępna od wersji Python 2.2W rzeczywistości możesz symulować
C#
metodę pobierającą i ustawiającą za pomocą tej prostej sztuczki:Następnie użyj go podobnie jak w
C#
:Po prostu deklaruje statyczną zmienną lokalną w funkcji, która będzie odgrywać rolę get / set, ponieważ jest to jedyny sposób dzielenia się zmienną za pomocą metod get i set, bez uczynienia jej globalną dla klasy lub pliku.
źródło