Czy Python ma zmienne "prywatne" w klasach?

Pochodzę ze świata Javy i czytam Bruce' a Eckelsa Python 3 Patterns, Recipes and Idioms.

Czytając o klasach, można powiedzieć, że w Pythonie nie ma potrzeby deklarowania zmiennych instancji. Wystarczy użyć ich w konstruktorze i bum, są tam.

Więc 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 dowolny obiekt klasy {[2] } może po prostu zmienić wartość zmiennej s 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órej nikt poza klasą nie ma dostępu.

Dlaczego nie jest to wymagane w Pythonie?

Author: Zags, 2009-10-29

11 answers

To kulturowe. W Pythonie nie piszesz do instancji ani zmiennych klas innych klas. W Javie nic nie stoi na przeszkodzie, aby zrobić to samo, jeśli naprawdę chcesz-w końcu zawsze możesz edytować źródło samej klasy, aby osiągnąć ten sam efekt. Python rzuca pozory bezpieczeństwa i zachęca programistów do odpowiedzialności. W praktyce działa to bardzo ładnie.

Jeśli z jakiegoś powodu chcesz emulować prywatne zmienne, zawsze możesz użyć prefiksu __ z PEP 8 . Python zniekształca nazwy zmiennych, takich jak __foo tak, że nie są one łatwo widoczne dla kodu poza klasą, która je zawiera (chociaż ty możesz obejść je, jeśli jesteś wystarczająco zdeterminowany, tak jak ty możesz obejść zabezpieczenia Javy, Jeśli nad tym pracujesz).

Zgodnie z tą samą konwencją przedrostek _ oznacza trzymaj się z daleka, nawet jeśli technicznie nie jesteś w stanie tego zrobić . Nie bawisz się zmiennymi innej klasy, które wygląd __foo lub _bar.

 780
Author: Kirk Strauser,
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-02 05:16:58

Prywatne zmienne w Pythonie to mniej więcej hack: interpreter celowo zmienia nazwę zmiennej.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

Teraz, jeśli spróbujesz uzyskać dostęp __var Poza definicją klasy, zakończy się to niepowodzeniem:

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

Ale można to łatwo ujść na sucho:

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

Prawdopodobnie wiesz, że metody w OOP są wywoływane w ten sposób: x.printVar() => A.printVar(x), Jeśli {[5] } może uzyskać dostęp do jakiegoś pola w x, to pole to może być również dostępne poza A.printVar()...w końcu tworzone są funkcje do wielokrotnego użytku, nie ma specjalnej władzy nad oświadczeniami wewnątrz.

Gra jest inna, gdy zaangażowany jest kompilator (prywatność jest koncepcją poziomu kompilatora ). Wie o definicji klasy z modyfikatorami kontroli dostępu, więc może popełnić błąd, jeśli reguły nie są przestrzegane podczas kompilacji

 109
Author: watashiSHUN,
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-05-26 06:53:13

Jak słusznie wspomniano w wielu komentarzach powyżej, nie zapominajmy o głównym celu modyfikatorów dostępu: aby pomóc użytkownikom kodu zrozumieć, co ma się zmienić, a czego nie. Kiedy widzisz prywatne pole, nie zadzierasz z nim. Jest to więc głównie cukier składniowy, który jest łatwo osiągalny w Pythonie przez _ i__.

 19
Author: Ardavan,
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-11-17 05:17:25

"w Javie uczono nas o zmiennych publicznych/prywatnych / chronionych"

" Dlaczego nie jest to wymagane w Pythonie?"

Z tego samego powodu nie jest wymagane w Javie.

Możesz używać lub nie używać private i protected.

Jako programista Python i Java odkryłem, że private i protected są bardzo, bardzo ważnymi koncepcjami projektowymi. Ale w praktyce, w dziesiątkach tysięcy linii Javy i Pythona, nigdy faktycznie nie używałem private lub protected.

Dlaczego nie? Oto moje pytanie " przed kim?" Inni programiści w moim zespole? Mają źródło. Co oznacza Ochrona, gdy mogą ją zmienić? Inni programiści z innych zespołów? Pracują dla tej samej firmy. Mogą ... przez telefon ... zdobyć źródło. Klienci? Jest to programowanie typu work-for-hire (ogólnie). Klienci (ogólnie) są właścicielami kodu.

Więc, kogo-dokładnie-chronię skąd?

Racja. Schizofreniczny socjopata, który nie chciał czytać komentarzy API.
 14
Author: S.Lott,
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-10-29 02:28:33

Istnieje zmienność zmiennych prywatnych w konwencji podkreślenia.

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

Istnieją pewne subtelne różnice, ale ze względu na ideologiczną czystość wzorca programowania, jest wystarczająco dobry.

Są tam przykłady @ prywatnych dekoratorów, które ściślej realizują koncepcję, ale YMMV. Prawdopodobnie można również napisać definicję klasy, która używa meta

 10
Author: Shayne,
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-16 12:41:34

Python ma ograniczone wsparcie dla prywatnych identyfikatorów, dzięki funkcji, która automatycznie dodaje nazwę klasy do dowolnych identyfikatorów zaczynających się od dwóch podkreślników. Jest to w większości przejrzyste dla programisty, ale efekt netto jest taki, że dowolne zmienne nazwane w ten sposób mogą być używane jako zmienne prywatne.

Zobacz TUTAJ Aby uzyskać więcej na ten temat.

Ogólnie rzecz biorąc, implementacja w Pythonie orientacji obiektów jest nieco prymitywna w porównaniu do innych języków. Ale lubię właściwie to. Jest to bardzo prosta koncepcyjnie implementacja i dobrze pasuje do dynamicznego stylu języka.

 8
Author: Dan Olson,
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-10-29 01:59:36

Używam prywatnych zmiennych tylko wtedy, gdy muszę robić inne rzeczy podczas pisania lub czytania ze zmiennej i jako takie muszę wymusić użycie settera i/lub gettera.

Znowu to idzie do kultury, jak już wspomniano. Pracowałem nad projektami, w których czytanie i pisanie zmiennych innych klas było darmowe dla wszystkich. Kiedy jedna z implementacji stała się przestarzała, identyfikacja wszystkich ścieżek kodu, które używały tej funkcji, zajęła dużo więcej czasu. Kiedy Korzystanie z seterów i getterów było wymuszone, Instrukcja debug może być łatwo napisana, aby stwierdzić, że przestarzała metoda została wywołana i ścieżka kodu, która ją wywołuje.

Kiedy jesteś w projekcie, w którym każdy może napisać rozszerzenie, powiadamianie Użytkowników o przestarzałych metodach, które mają zniknąć w kilku wydaniach, jest więc niezbędne, aby utrzymać uszkodzenie modułu na minimalnym poziomie przy aktualizacjach.

Więc moja odpowiedź brzmi: jeśli ty i twoi koledzy utrzymujecie prosty zestaw kodu, Ochrona zmiennych klas nie zawsze jest konieczna. Jeśli piszesz system rozszerzalny, staje się to konieczne, gdy wprowadzone zostaną zmiany w rdzeniu, które muszą zostać przechwycone przez wszystkie rozszerzenia za pomocą kodu.

 7
Author: BlueEagle,
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-04-01 09:28:42

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 rozwoju, dlatego niektóre poziomy ochrony nie są tak rygorystyczne przestrzegane w Pythonie. Możesz użyć "_ _ " w członku klasy, działa poprawnie, ale nie wygląda wystarczająco dobrze - każdy dostęp do takiego pola zawiera te znaki.

Również, można zauważyć, że Python OOP concept nie jest doskonały, smaltalk lub ruby znacznie bliżej do czystego OOP koncepcja. Nawet C# czy Java są bliżej.

Python jest bardzo dobrym narzędziem. Ale jest to uproszczony język OOP. Uproszczone składniowo i koncepcyjnie. Głównym celem istnienia Pythona jest zapewnienie programistom możliwości pisania łatwego do odczytu kodu o wysokim poziomie abstrakcji w bardzo szybki sposób.

 6
Author: user711294,
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
2011-07-17 06:00:14

Jak wspomniano wcześniej, możesz wskazać, że zmienna lub metoda jest prywatna, dodając przedrostek podkreślenia. Jeśli nie uważasz, że to wystarczy, zawsze możesz użyć dekoratora property. Oto przykład:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

W ten sposób ktoś lub coś, co odwołuje się do bar w rzeczywistości odwołuje się do wartości zwracanej funkcji bar, a nie do samej zmiennej. Jeśli jednak ktoś naprawdę chciał, mógł po prostu użyć _bar i przypisać mu nową wartość. Nie ma niezawodnego sposobu, aby uniemożliwić komuś dostęp do zmiennych i metod, które chcesz ukryć, jak już wielokrotnie mówiono. Jednak użycie property jest najczystszym komunikatem, który możesz wysłać, że zmienna nie ma być edytowana. property może być również używany do bardziej złożonych ścieżek dostępu getter/setter/deleter, jak wyjaśniono tutaj: https://docs.python.org/3/library/functions.html#property

 5
Author: Isaac Saffold,
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-03 14:24:47

Sorry chłopaki za "wskrzeszenie" wątku, ale mam nadzieję, że to komuś pomoże:

W Python3 jeśli chcesz po prostu "enkapsulować" atrybuty klasy, tak jak w Javie, możesz zrobić to samo w następujący sposób:

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

To instantiate this do:

ss = Simple("lol")
ss.show()

Zauważ, że: print(ss.__s) wyrzuci błąd.

W praktyce Python3 zaciemni globalną nazwę atrybutu. Zmieniając to jak atrybut" prywatny", jak w Javie. Nazwa atrybutu jest nadal globalna, ale w niedostępny sposób, podobnie jak atrybut prywatny w innych językach.

Ale nie bój się tego. Nieważne. To też robi swoje. ;)
 3
Author: Ferrarezi,
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-04-21 16:06:06

Python nie ma żadnych prywatnych zmiennych, takich jak C++ czy Java. Możesz uzyskać dostęp do dowolnej zmiennej członkowskiej w dowolnym momencie, jeśli chcesz. Jednak nie potrzebujesz prywatnych zmiennych w Pythonie, ponieważ w Pythonie nie jest źle ujawniać zmiennych członkowskich klas. Jeśli masz potrzebę hermetyzacji zmiennej członkowskiej, możesz to zrobić, używając" @property " później bez łamania istniejącego kodu klienta.

W Pythonie pojedynczy podkreślnik " _ " jest używany do wskazania, że metoda lub zmienna nie jest uważany za część publicznego api klasy i że ta część api może się zmieniać między różnymi wersjami. Możesz użyć tych metod/zmiennych, ale twój kod może się zepsuć, jeśli używasz nowszej wersji tej klasy.

Podwójny podkreślnik "_ _ "nie oznacza " zmiennej prywatnej". Używa się go do definiowania zmiennych, które są "klasami lokalnymi" i które nie mogą być łatwo nadpisane przez podklasy. Zmienia nazwę zmiennych.

Dla przykład:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

Self._Nazwa _foobar jest automatycznie zmieniana na self._ A _ _ foobar w klasie A. W Klasie B jest zmasakrowany do siebie._ B _ _ foobar. Tak więc każda podklasa może zdefiniować własną zmienną _ _ foobar bez nadpisywania jej zmiennych nadrzędnych. Ale nic nie stoi na przeszkodzie, aby uzyskać dostęp do zmiennych zaczynających się od podwójnego podkreślenia. Jednak Wymaganie nazw uniemożliwia przypadkowe wywołanie tych zmiennych /metod.

Zdecydowanie polecam obejrzenie rozmowy Raymonda Hettingersa " Pythons class development toolkit " z Pycon 2013 (powinien być dostępny na Youtube), który daje dobry przykład dlaczego i jak należy używać zmiennych @ property i "__"-instance.

 -1
Author: Hatatister,
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-06-26 22:23:39