Heeft Python “private” variabelen in klassen?

Ik kom uit de Java-wereld en lees Bruce Eckels’ Python 3 Patterns, Recipes and Idioms.

Terwijl we over klassen lezen, wordt verder gezegd dat het in Python niet nodig is om instantievariabelen te declareren. Je gebruikt ze gewoon in de constructor, en boem, ze zijn er.

Dus bijvoorbeeld:

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

Als dat waar is, kan elk object van klasse Simplede waarde van variabele sbuiten de klasse wijzigen.

Bijvoorbeeld:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

In Java hebben we geleerd over publieke/private/beschermde variabelen. Die trefwoorden zijn logisch omdat je soms variabelen in een klasse wilt waartoe niemand buiten de klasse toegang heeft.

Waarom is dat niet vereist in Python?


Antwoord 1, autoriteit 100%

Het is cultureel. In Python schrijf je niet naar de instantie of klassevariabelen van andere klassen. In Java weerhoudt niets u ervan hetzelfde te doen als u echtdat wilt – u kunt tenslotte altijd de bron van de klasse zelf bewerken om hetzelfde effect te bereiken. Python laat die pretentie van veiligheid vallen en moedigt programmeurs aan om verantwoordelijkheid te nemen. In de praktijk werkt dit erg prettig.

Als je om de een of andere reden privévariabelen wilt emuleren, kun je altijd het voorvoegsel __van PEP 8. Python vervormt de namen van variabelen zoals __foozodat ze niet gemakkelijk zichtbaar zijn voor code buiten de klasse die ze bevat (hoewel je er kuntomheen als je vastbesloten bent genoeg, net zoals u kuntde beveiligingen van Java omzeilen als u eraan werkt).

Volgens dezelfde conventie betekent het voorvoegsel _blijf weg, zelfs als je technisch gezien niet verhinderd wordt om dit te doen. Je speelt niet met variabelen van een andere klasse die eruitzien als __fooof _bar.


Antwoord 2, autoriteit 18%

Privévariabelen in python zijn min of meer een hack: de interpreter hernoemt de variabele opzettelijk.

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

Als je nu probeert toegang te krijgen tot __varbuiten de klassedefinitie, zal het mislukken:

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

Maar je kunt hier gemakkelijk mee wegkomen:

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

U weet waarschijnlijk dat methoden in OOP als volgt worden aangeroepen: x.printVar() => A.printVar(x), als A.printVar()toegang heeft tot een veld in x, is dit veld ook toegankelijk buitenA.printVar()…per slot van rekening worden functies gemaakt voor herbruikbaarheid, er is geen speciale bevoegdheid gegeven aan de instructies binnenin.

Het spel is anders als er een compiler bij betrokken is (privacy is een concept op compilerniveau). Het kent klassedefinitie met modifiers voor toegangscontrole, zodat het fouten kan maken als de regels niet worden gevolgd tijdens het compileren


Antwoord 3, autoriteit 3%

Zoals terecht vermeld in veel van de bovenstaande opmerkingen, laten we het hoofddoel van Access Modifiers niet vergeten: gebruikers van code helpen begrijpen wat er zou moeten veranderen en wat niet zou moeten. Als je een privéveld ziet, ga je er niet mee rommelen. Het is dus meestal syntactische suiker die in Python gemakkelijk wordt bereikt door de _ en __.


Antwoord 4, autoriteit 2%

Er is een variatie van privévariabelen in de conventie voor onderstrepingstekens.

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'

Er zijn enkele subtiele verschillen, maar omwille van de ideologische zuiverheid van het programmeerpatroon is het goed genoeg.

Er zijn voorbeelden van @private decorateurs die het concept nauwkeuriger implementeren, maar YMMV. Je zou misschien ook een klassedefinitie kunnen schrijven die meta gebruikt


Antwoord 5

Zoals eerder vermeld, kunt u aangeven dat een variabele of methode privé is door er een onderstrepingsteken voor te zetten. Als je denkt dat dit niet genoeg is, kun je altijd de propertydecorateur gebruiken. Hier is een voorbeeld:

class Foo:
    def __init__(self, bar):
        self._bar = bar
    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

Op deze manier verwijst iemand of iets dat verwijst naar bareigenlijk naar de geretourneerde waarde van de functie barin plaats van naar de variabele zelf, en daarom is het toegankelijk, maar niet veranderd. Als iemand het echter echt zou willen, kunnen ze gewoon _bargebruiken en er een nieuwe waarde aan toewijzen. Er is geen onfeilbare manier om te voorkomen dat iemand toegang krijgt tot variabelen en methoden die u wilt verbergen, zoals herhaaldelijk is gezegd. Het gebruik van propertyis echter de duidelijkste boodschap die u kunt sturen dat een variabele niet moet worden bewerkt. propertykan ook worden gebruikt voor complexere getter/setter/deleter-toegangspaden, zoals hier wordt uitgelegd: https://docs.python.org/3/library/functions.html#property


Antwoord 6

Python heeft geen privévariabelen zoals C++ of Java. U kunt desgewenst ook op elk moment toegang krijgen tot elke lidvariabele. U hebt echter geen privévariabelen nodig in Python, omdat het in Python niet slecht is om uw klassenlidvariabelen bloot te leggen. Als u een lidvariabele moet inkapselen, kunt u dit later doen door “@property” te gebruiken zonder de bestaande klantcode te breken.

In python wordt het enkele onderstrepingsteken “_” gebruikt om aan te geven dat een methode of variabele niet wordt beschouwd als onderdeel van de openbare api van een klasse en dat dit deel van de api tussen verschillende versies kan veranderen. Je kunt deze methoden/variabelen gebruiken, maar je code kan kapot gaan als je een nieuwere versie van deze klasse gebruikt.

Het dubbele onderstrepingsteken “__” betekent niet een “private variabele”. Je gebruikt het om variabelen te definiëren die “class local” zijn en die niet gemakkelijk kunnen worden overschreven door subklassen. Het verminkt de naam van de variabelen.

Bijvoorbeeld:

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.__foobar’s naam wordt automatisch verminkt tot self._A__foobar in klasse A. In klasse B wordt het verminkt tot self._B__foobar. Dus elke subklasse kan zijn eigen variabele __foobar definiëren zonder de bovenliggende variabele(n) te overschrijven. Maar niets weerhoudt u ervan om toegang te krijgen tot variabelen die beginnen met dubbele onderstrepingstekens. Het mangelen van namen voorkomt echter dat je deze variabelen /methoden incidenteel aanroept.

Ik raad je ten zeerste aan om Raymond Hettinger’s python’s class ontwikkeling toolkit van pycon 2013, Wat een goed voorbeeld geeft, waarom en hoe u @Property en “__” – exemplaarvariabelen moet gebruiken.

Als u openbare variabelen hebt blootgesteld en u de behoefte hebt om ze in te loggen, kunt u @Property gebruiken. Daarom kunt u beginnen met de eenvoudigste oplossing mogelijk. U kunt het publiek van de lidstaten achterlaten, tenzij u een concrete reden hebt om dit niet te doen. Hier is een voorbeeld:

class Distance:
    def __init__(self, meter):
        self.meter = meter
d = Distance(1.0)
print(d.meter)
# prints 1.0
class Distance:
    def __init__(self, meter):
        # Customer request: Distances must be stored in millimeters.
        # Public available internals must be changed.
        # This would break client code in C++.
        # This is why you never expose public variables in C++ or Java.
        # However, this is python.
        self.millimeter = meter * 1000
    # In python we have @property to the rescue.
    @property
    def meter(self):
        return self.millimeter *0.001
    @meter.setter
    def meter(self, value):
        self.millimeter = meter * 1000
d = Distance(1.0)
print(d.meter)
# prints 1.0

Antwoord 7

“In Java zijn we onderwezen over openbare / private / beschermde variabelen”

“Waarom is dat niet vereist in Python?”

Om dezelfde reden is het niet verplicht in Java.

U bent vrij om te gebruiken – of niet gebruiken privateen protected.

Als Python en Java-programmeur heb ik gevonden dat privateen protectedzeer belangrijk ontwerpconcepten zijn. Maar als een praktische kwestie, heb ik in tienduizenden lijnen van Java en Python nooit eigenlijk gebruikt privateof protected.

Waarom niet?

Hier is mijn vraag “Beschermd van wie?”

andere programmeurs in mijn team? Ze hebben de bron. Wat betekent beveiligd als ze het kunnen veranderen?

andere programmeurs op andere teams? Ze werken voor hetzelfde bedrijf. Ze kunnen – met een telefoongesprek – krijg de bron.

clients? Het is work-for-hire programmering (in het algemeen). De klanten hebben de code in het algemeen).

Dus, wie – precies – ben ik ervan tegen?


Antwoord 8

Python heeft beperkte ondersteuning voor particuliere ID’s, via een functie die automatisch de klassennaam oploopt op alle identificaties die beginnen met twee onderstrepingstekens. Dit is voor het grootste deel transparant naar de programmeur, maar het netto-effect is dat alle variabelen die op deze manier worden genoemd kunnen worden gebruikt als privévariabelen.

Zie hier voor meer daarover.

In het algemeen is de implementatie van de implementatie van Python van objectoriëntatie een beetje primitief in vergelijking met andere talen. Maar ik geniet ervan, eigenlijk. Het is een zeer conceptueel eenvoudige implementatie en past goed bij de dynamische stijl van de taal.


Antwoord 9

De enige keer dat ik ooit privévariabelen gebruik, is wanneer ik andere dingen moet doen bij het schrijven of lezen van de variabele en als zodanig moet ik het gebruik van een setter en / of getter dwingen.

Ook dit gaat weer over cultuur, zoals al gezegd. Ik heb aan projecten gewerkt waarbij het lezen en schrijven van andere klassenvariabelen voor iedereen gratis was. Toen een implementatie verouderd raakte, duurde het veel langer om alle codepaden te identificeren die die functie gebruikten. Wanneer het gebruik van setters en getters werd afgedwongen, kon eenvoudig een debug-instructie worden geschreven om te identificeren dat de verouderde methode was aangeroepen en het codepad dat deze aanroept.

Als je aan een project werkt waar iedereen een extensie kan schrijven, is het essentieel om gebruikers op de hoogte te stellen van verouderde methoden die in een paar releases zullen verdwijnen. Daarom is het essentieel om modulebreuk bij upgrades tot een minimum te beperken.

Dus mijn antwoord is; als jij en je collega’s een eenvoudige codeset onderhouden, is het niet altijd nodig om klassevariabelen te beschermen. Als u een uitbreidbaar systeem schrijft, wordt het noodzakelijk wanneer er wijzigingen in de kern worden aangebracht die door alle extensies met behulp van de code moeten worden opgevangen.


Antwoord 10

Sorry jongens voor het “opnieuw doen herleven” van de thread, maar ik hoop dat dit iemand zal helpen:

Als u in Python3 alleen de klassekenmerken wilt “inkapselen”, zoals in Java, kunt u hetzelfde als volgt doen:

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

Om dit te instantiëren:

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

Merk op dat: print(ss.__s)een foutmelding geeft.

In de praktijk zal Python3 de naam van de wereldwijde attribuut verdraaien. Dit draaien als een “privé” -attribuut, zoals in Java. De naam van de attribuut is nog steeds globaal, maar op een ontoegankelijke manier, zoals een privé-attribuut in andere talen.

Maar wees er niet bang voor. Het maakt niet uit. Het is ook het werk. 😉


Antwoord 11

Privé en beschermde concepten zijn erg belangrijk. Maar Python – Gewoon een tool voor prototyping en snelle ontwikkeling met beperkte middelen beschikbaar voor ontwikkeling, daarom zijn sommige beschermingsniveaus niet zo streng gevolgd in Python. U kunt “__” in de klasselement gebruiken, het werkt goed, maar ziet er niet goed genoeg uit – elke toegang tot een dergelijk veld bevat deze tekens.

Ook, u kunt opgemerkt dat Python Oop Concept niet perfect is, smaltalk of robijns veel dichter bij het zuivere OOP-concept. Zelfs C # of Java zijn dichterbij.

Python is een zeer goede tool. Maar het is een vereenvoudigde OOP-taal. Syntactisch en conceptueel vereenvoudigd. Het belangrijkste doel van het bestaan ​​van Python is om de mogelijkheid van de ontwikkelaars te brengen om een ​​gemakkelijk leesbare code met een hoge abstractieniveau op een zeer snelle manier te schrijven.


Antwoord 12

Over bronnen (om de toegangsrechten te wijzigen en aldus omzeiltaal inkapseling zoals Java of C++):
Je hebt niet altijd de bronnen en zelfs als je dat doet, worden de bronnen beheerd door een systeem dat alleen bepaalde programmeurs toestaat om toegang te krijgen tot een bron (in een professionele context). Vaak is elke programmeur verantwoordelijk voor bepaalde klassen en weet daarom wat hij kan en niet kan doen. De bronbeheer vergrendelt ook de bronnen die worden gewijzigd en natuurlijk beheert de toegangsrechten van programmeurs.

Dus ik vertrouw meer in software dan in de mens, door ervaring. Dus Conventie is goed, maar meerdere beveiligingen zijn beter, zoals Access Management (Real Private Variable) + Bronnenbeheer.

Other episodes