Wenn Sie Zweifel haben, lassen Sie es "öffentlich" - ich meine, fügen Sie nichts hinzu, um den Namen Ihres Attributs zu verschleiern. Wenn Sie eine Klasse mit einem internen Wert haben, kümmern Sie sich nicht darum. Anstatt zu schreiben:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
schreibe dies standardmäßig:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
Dies ist mit Sicherheit eine kontroverse Vorgehensweise. Python-Neulinge hassen es einfach und sogar einige alte Python-Leute verachten diese Standardeinstellung - aber es ist trotzdem die Standardeinstellung. Ich empfehle Ihnen daher, sie zu befolgen, auch wenn Sie sich unwohl fühlen.
Wenn Sie wirklich die Nachricht "Kann dies nicht berühren!" Senden möchten Für Ihre Benutzer besteht die übliche Methode darin, der Variablen einen Unterstrich voranzustellen. Dies ist nur eine Konvention, aber die Leute verstehen sie und gehen beim Umgang mit solchen Dingen doppelt vorsichtig vor:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
Dies kann auch nützlich sein, um Konflikte zwischen Eigenschaftsnamen und Attributnamen zu vermeiden:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Was ist mit dem doppelten Unterstrich? Nun, die Magie des doppelten Unterstrichs wird hauptsächlich verwendet , um ein versehentliches Überladen von Methoden und Namenskonflikten mit den Attributen von Oberklassen zu vermeiden . Es kann sehr nützlich sein, wenn Sie eine Klasse schreiben, von der erwartet wird, dass sie um ein Vielfaches erweitert wird.
Wenn Sie es für andere Zwecke verwenden möchten, können Sie dies, aber es ist weder üblich noch empfohlen.
BEARBEITEN : Warum ist das so? Nun, der übliche Python-Stil betont nicht, Dinge privat zu machen - im Gegenteil! Dafür gibt es viele Gründe - die meisten sind umstritten ... Lassen Sie uns einige davon sehen.
Python hat Eigenschaften
Die meisten OO-Sprachen verwenden heutzutage den umgekehrten Ansatz: Was nicht verwendet werden sollte, sollte nicht sichtbar sein, daher sollten Attribute privat sein. Theoretisch würde dies zu besser verwaltbaren, weniger gekoppelten Klassen führen, da niemand die Werte innerhalb der Objekte rücksichtslos ändern würde.
Es ist jedoch nicht so einfach. Zum Beispiel Java - Klassen haben eine Menge Attribute haben und Getter , die nur bekommen die Werte und Setter , die gerade gesetzt , die Werte. Sie benötigen beispielsweise sieben Codezeilen, um ein einzelnes Attribut zu deklarieren - was ein Python-Programmierer als unnötig komplex bezeichnen würde. In der Praxis schreiben Sie einfach diese ganze Menge Code, um ein öffentliches Feld zu erhalten, da Sie den Wert mithilfe der Getter und Setter ändern können.
Warum sollten Sie diese standardmäßig private Richtlinie befolgen? Machen Sie Ihre Attribute einfach standardmäßig öffentlich. Dies ist in Java natürlich problematisch, da Sie alle Änderungen vornehmen müssen, wenn Sie Ihrem Attribut eine Validierung hinzufügen möchten
person.age = age;
in Ihrem Code zu, lassen Sie uns sagen,
person.setAge(age);
setAge()
Sein:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
In Java (und anderen Sprachen) werden standardmäßig Getter und Setter verwendet, da das Schreiben lästig sein kann, Sie jedoch viel Zeit sparen können, wenn Sie sich in der von mir beschriebenen Situation befinden.
Sie müssen dies jedoch nicht in Python tun, da Python Eigenschaften hat. Wenn Sie diese Klasse haben:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
Wenn Sie sich entscheiden, das Alter zu überprüfen, müssen Sie die person.age = age
Teile Ihres Codes nicht ändern . Fügen Sie einfach eine Eigenschaft hinzu (wie unten gezeigt)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Wenn Sie dies tun und trotzdem verwenden können person.age = age
, warum sollten Sie dann private Felder sowie Getter und Setter hinzufügen?
(Siehe auch Python ist nicht Java und dieser Artikel über die Nachteile der Verwendung von Gettern und Setzern .)
Alles ist sowieso sichtbar - und der Versuch, sich zu verstecken, erschwert Ihre Arbeit
Selbst in Sprachen, in denen private Attribute vorhanden sind, können Sie über eine Art Reflexions- / Selbstbeobachtungsbibliothek darauf zugreifen. Und die Leute tun es oft, in Rahmenbedingungen und zur Lösung dringender Bedürfnisse. Das Problem ist, dass Introspektionsbibliotheken nur eine schwierige Methode sind, um das zu tun, was Sie mit öffentlichen Attributen tun können.
Da Python eine sehr dynamische Sprache ist, ist es nur kontraproduktiv, diese Belastung Ihren Klassen hinzuzufügen.
Das Problem ist nicht erkennbar - es ist erforderlich gesehen werden
Für einen Pythonista ist die Kapselung nicht die Unfähigkeit, die Interna von Klassen zu sehen, sondern die Möglichkeit, das Betrachten zu vermeiden. Ich meine, Kapselung ist die Eigenschaft einer Komponente, die es ermöglicht, sie zu verwenden, ohne dass sich der Benutzer um die internen Details kümmert. Wenn Sie eine Komponente verwenden können, ohne sich um ihre Implementierung zu kümmern, ist sie gekapselt (nach Meinung eines Python-Programmierers).
Wenn Sie Ihre Klasse so geschrieben haben, dass Sie sie verwenden können, ohne über Implementierungsdetails nachdenken zu müssen, gibt es kein Problem, wenn Sie aus irgendeinem Grund in die Klasse schauen möchten . Der Punkt ist: Ihre API sollte gut sein und der Rest sind Details.
Guido sagte es
Nun, das ist nicht umstritten: Er sagte es tatsächlich . (Suchen Sie nach "offenem Kimono".)
Das ist Kultur
Ja, es gibt einige Gründe, aber keinen kritischen Grund. Dies ist hauptsächlich ein kultureller Aspekt der Programmierung in Python. Ehrlich gesagt könnte es auch umgekehrt sein - ist es aber nicht. Sie können auch genauso gut umgekehrt fragen: Warum verwenden einige Sprachen standardmäßig private Attribute? Aus dem gleichen Hauptgrund wie für die Python-Praxis: Weil es die Kultur dieser Sprachen ist und jede Wahl Vor- und Nachteile hat.
Da es diese Kultur bereits gibt, sind Sie gut beraten, ihr zu folgen. Andernfalls ärgern Sie sich über Python-Programmierer, die Sie auffordern, das __
aus Ihrem Code zu entfernen , wenn Sie eine Frage in Stack Overflow stellen :)
Erstens - Was ist Name Mangling?
Name Mangeln wird aufgerufen , wenn Sie in einer Klassendefinition und Verwendung sind
__any_name
oder__any_name_
, das ist zwei (oder mehr) führenden Unterstrichen und höchstens ein Unterstrich Hinter.Und nun:
Die angebliche Verwendung besteht darin, zu verhindern, dass Unterklassen ein Attribut verwenden, das die Klasse verwendet.
Ein möglicher Wert besteht darin, Namenskollisionen mit Unterklassen zu vermeiden, die das Verhalten überschreiben möchten, damit die übergeordnete Klassenfunktionalität wie erwartet funktioniert. Das Beispiel in der Python-Dokumentation ist jedoch nicht durch Liskov ersetzbar, und es fallen mir keine Beispiele ein, bei denen ich dies nützlich gefunden habe.
Die Nachteile sind, dass es die kognitive Belastung für das Lesen und Verstehen einer Codebasis erhöht, insbesondere beim Debuggen, bei dem der doppelte Unterstrich in der Quelle und ein verstümmelter Name im Debugger angezeigt werden.
Mein persönlicher Ansatz ist es, dies absichtlich zu vermeiden. Ich arbeite an einer sehr großen Codebasis. Die seltenen Verwendungszwecke ragen wie ein schmerzender Daumen heraus und scheinen nicht gerechtfertigt zu sein.
Sie müssen sich dessen bewusst sein, damit Sie es wissen, wenn Sie es sehen.
PEP 8
PEP 8 , dem Style Guide für die Python-Standardbibliothek, heißt es derzeit (gekürzt):
Wie funktioniert es?
Wenn Sie in einer Klassendefinition zwei Unterstriche voranstellen (ohne doppelte Unterstriche zu beenden), wird der Name entstellt, und dem Objekt wird ein Unterstrich gefolgt vom Klassennamen vorangestellt:
Beachten Sie, dass Namen nur dann entstellt werden, wenn die Klassendefinition analysiert wird:
Außerdem haben Python-Neulinge manchmal Probleme zu verstehen, was vor sich geht, wenn sie nicht manuell auf einen Namen zugreifen können, den sie in einer Klassendefinition definiert sehen. Dies ist kein starker Grund dagegen, aber es ist etwas zu beachten, wenn Sie ein lernendes Publikum haben.
Ein Unterstrich?
Wenn Benutzer beabsichtigen, ihre Hände von einem Attribut fernzuhalten, verwende ich normalerweise nur den einen Unterstrich. Dies liegt jedoch daran, dass Unterklassen in meinem mentalen Modell Zugriff auf den Namen haben (den sie immer haben, da sie den leicht erkennen können verstümmelter Name sowieso).
Wenn ich Code überprüfen würde, der das
__
Präfix verwendet, würde ich fragen, warum sie Namensverknüpfungen aufrufen und ob sie mit einem einzelnen Unterstrich nicht genauso gut zurechtkommen könnten, wobei zu berücksichtigen ist, dass Unterklassen dieselben Namen für die Klasse und wählen Klassenattribut Trotzdem kommt es zu einer Namenskollision.quelle
Ich würde nicht sagen, dass Übung besseren Code erzeugt. Sichtbarkeitsmodifikatoren lenken Sie nur von der eigentlichen Aufgabe ab und erzwingen als Nebeneffekt, dass Ihre Benutzeroberfläche wie beabsichtigt verwendet wird. Im Allgemeinen verhindert das Erzwingen der Sichtbarkeit, dass Programmierer Dinge durcheinander bringen, wenn sie die Dokumentation nicht richtig gelesen haben.
Eine weitaus bessere Lösung ist der von Python empfohlene Weg: Ihre Klassen und Variablen sollten gut dokumentiert und ihr Verhalten klar sein. Die Quelle sollte verfügbar sein. Dies ist eine weitaus erweiterbarere und zuverlässigere Methode zum Schreiben von Code.
Meine Strategie in Python lautet:
Vor allem sollte klar sein, was alles macht. Dokumentieren Sie es, wenn jemand anderes es verwenden wird. Dokumentieren Sie es, wenn Sie möchten, dass es in einem Jahr nützlich ist.
Als Randnotiz sollten Sie eigentlich mit geschützt in diesen anderen Sprachen arbeiten: Sie wissen nie, dass Ihre Klasse später geerbt werden könnte und wofür sie verwendet werden könnte. Am besten schützen Sie nur die Variablen, von denen Sie sicher sind, dass sie nicht von Fremdcode verwendet werden können oder sollten.
quelle
Sie sollten nicht mit privaten Daten beginnen und diese bei Bedarf veröffentlichen. Sie sollten zunächst die Schnittstelle Ihres Objekts herausfinden. Das heißt, Sie sollten zunächst herausfinden, was die Welt sieht (das öffentliche Zeug) und dann herausfinden, welches private Zeug dafür notwendig ist.
Andere Sprachen machen es schwierig, das, was einst öffentlich war, privat zu machen. Dh ich werde viel Code brechen, wenn ich meine Variable privat oder geschützt mache. Bei Eigenschaften in Python ist dies jedoch nicht der Fall. Vielmehr kann ich die gleiche Schnittstelle auch bei einer Neuordnung der internen Daten beibehalten.
Der Unterschied zwischen _ und __ besteht darin, dass Python tatsächlich versucht, letzteres durchzusetzen. Natürlich ist es nicht wirklich anstrengend, aber es macht es schwierig. Wenn _ anderen Programmierern lediglich die Absicht mitteilt, können sie diese auf eigene Gefahr ignorieren. Das Ignorieren dieser Regel ist jedoch manchmal hilfreich. Beispiele hierfür sind Debugging, temporäre Hacks und die Arbeit mit Code von Drittanbietern, der nicht so verwendet werden soll, wie Sie ihn verwenden.
quelle
Es gibt bereits viele gute Antworten darauf, aber ich werde eine andere anbieten. Dies ist teilweise auch eine Reaktion auf Leute, die immer wieder sagen, dass doppelter Unterstrich nicht privat ist (es ist wirklich so).
Wenn Sie sich Java / C # ansehen, haben beide private / protected / public. All dies sind Konstrukte zur Kompilierungszeit . Sie werden nur zum Zeitpunkt der Kompilierung durchgesetzt. Wenn Sie Reflection in Java / C # verwenden, können Sie problemlos auf die private Methode zugreifen.
Jedes Mal, wenn Sie eine Funktion in Python aufrufen, verwenden Sie von Natur aus Reflection. Diese Codeteile sind in Python identisch.
Die "Punkt" -Syntax ist nur syntaktischer Zucker für den letzteren Code. Meistens, weil die Verwendung von getattr mit nur einem Funktionsaufruf bereits hässlich ist. Von da an wird es nur noch schlimmer.
Also damit kann es nicht Java / C # -Version von private geben, da Python den Code nicht kompiliert. Java und C # können zur Laufzeit nicht überprüfen, ob eine Funktion privat oder öffentlich ist, da diese Informationen nicht mehr vorhanden sind (und sie nicht wissen, woher die Funktion aufgerufen wird).
Mit diesen Informationen ist die Namensverflechtung des doppelten Unterstrichs am sinnvollsten, um "Privatität" zu erreichen. Wenn nun eine Funktion von der 'self'-Instanz aufgerufen wird und feststellt, dass sie mit' __ 'beginnt, führt sie genau dort den Namen mangling aus. Es ist nur mehr syntaktischer Zucker. Dieser syntaktische Zucker ermöglicht das Äquivalent von "privat" in einer Sprache, die nur die Reflexion für den Zugriff auf Datenelemente verwendet.
Haftungsausschluss: Ich habe noch nie jemanden aus der Python-Entwicklung so etwas sagen hören. Der wahre Grund für das Fehlen von "privat" ist kulturell, aber Sie werden auch feststellen, dass die meisten Skriptsprachen / interpretierten Sprachen keine privaten haben. Ein streng durchsetzbarer Privatmann ist nur zur Kompilierungszeit praktikabel.
quelle
Erstens: Warum möchten Sie Ihre Daten verbergen? Warum ist das so wichtig?
Meistens willst du es nicht wirklich tun, aber du tust es, weil andere es tun.
Wenn Sie wirklich wirklich wirklich nicht wollen, dass Leute etwas benutzen, fügen Sie eins hinzu Unterstrich davor hinzu. Das war's ... Pythonisten wissen, dass Dinge mit einem Unterstrich nicht jedes Mal garantiert funktionieren und sich ändern können, ohne dass Sie es wissen.
So leben wir und damit sind wir einverstanden.
Wenn Sie zwei Unterstriche verwenden, wird Ihre Klasse für die Unterklasse so schlecht, dass selbst Sie nicht so arbeiten möchten.
quelle
Die gewählte Antwort erklärt gut, wie Eigenschaften die Notwendigkeit privater Attribute beseitigen , aber ich möchte auch hinzufügen, dass Funktionen auf Modulebene die Notwendigkeit privater Methoden beseitigen .
Wenn Sie eine Methode auf Modulebene in eine Funktion umwandeln, entfernen Sie die Möglichkeit für Unterklassen, diese zu überschreiben. Das Verschieben einiger Funktionen auf die Modulebene ist pythonischer als der Versuch, Methoden mit Namensverknüpfung auszublenden.
quelle
Das folgende Code-Snippet erklärt alle verschiedenen Fälle:
kein Unterstrich (a)
Drucken aller gültigen Attribute des Testobjekts
Hier können Sie sehen, dass der Name von __a in _Test__a geändert wurde, um zu verhindern, dass diese Variable von einer der Unterklassen überschrieben wird. Dieses Konzept ist in Python als "Name Mangling" bekannt. Sie können folgendermaßen darauf zugreifen:
In ähnlicher Weise dient die Variable im Fall von _a nur dazu, den Entwickler darüber zu informieren, dass sie als interne Variable dieser Klasse verwendet werden soll. Der Python-Interpreter führt auch dann keine Aktionen aus, wenn Sie darauf zugreifen. Dies ist jedoch keine gute Vorgehensweise.
Auf eine Variable kann von überall aus zugegriffen werden, wie bei einer öffentlichen Klassenvariablen.
Hoffe die Antwort hat dir geholfen :)
quelle
Auf den ersten Blick sollte es das gleiche sein wie für andere Sprachen (unter "andere" meine ich Java oder C ++), aber es ist nicht so.
In Java haben Sie alle Variablen privat gemacht, auf die außerhalb nicht zugegriffen werden sollte. Gleichzeitig kann man dies in Python nicht erreichen, da es keine "Privatsphäre" gibt (wie eines der Python-Prinzipien sagt - "Wir sind alle Erwachsene"). Ein doppelter Unterstrich bedeutet also nur "Leute, benutzt dieses Feld nicht direkt". Dieselbe Bedeutung hat einen einzigen Unterstrich, der gleichzeitig keine Kopfschmerzen verursacht, wenn Sie von einer betrachteten Klasse erben müssen (nur ein Beispiel für ein mögliches Problem, das durch einen doppelten Unterstrich verursacht wird).
Daher würde ich Ihnen empfehlen, standardmäßig einen einzelnen Unterstrich für "private" Mitglieder zu verwenden.
quelle
"Wenn Sie Zweifel haben, ob eine Variable privat oder geschützt sein soll, ist es besser, privat zu gehen." - Ja, das gilt auch für Python.
Einige Antworten hier sagen über "Konventionen" aus, geben aber keine Links zu diesen Konventionen an. Der maßgebliche Leitfaden für Python, PEP 8, besagt ausdrücklich:
Die Unterscheidung zwischen öffentlich und privat sowie die Namensverfälschung in Python wurden in anderen Antworten berücksichtigt. Aus dem gleichen Link,
quelle