Ich weiß nicht, wann das Attribut privat sein soll und ob ich die Eigenschaft verwenden soll.
Ich habe kürzlich gelesen, dass Setter und Getter nicht pythonisch sind und ich sollte Property Decorator verwenden. Es ist in Ordnung.
Aber was ist, wenn ich ein Attribut habe, das nicht von außerhalb der Klasse festgelegt werden darf, sondern gelesen werden kann (schreibgeschütztes Attribut)? Sollte dieses Attribut privat sein, und mit privat meine ich so einen Unterstrich self._x
? Wenn ja, wie kann ich es dann lesen, ohne Getter zu verwenden? Die einzige Methode, die ich derzeit kenne, ist das Schreiben
@property
def x(self):
return self._x
Auf diese Weise kann ich Attribute lesen, obj.x
aber ich kann sie nicht festlegenobj.x = 1
dass es in Ordnung ist.
Aber sollte es mir wirklich etwas ausmachen, ein Objekt festzulegen, das nicht festgelegt werden darf? Vielleicht sollte ich es einfach verlassen. Andererseits kann ich keinen Unterstrich verwenden, da das Lesen obj._x
für den Benutzer ungerade ist. Daher sollte ich ihn verwenden, obj.x
und der Benutzer weiß nicht, dass er dieses Attribut nicht festlegen darf.
Was ist Ihre Meinung und Praxis?
quelle
self.x
und vertrauen Sie darauf, dass sich niemand ändern wirdx
. Wennx
es wichtig ist, sicherzustellen, dass dies nicht geändert werden kann, verwenden Sie eine Eigenschaft._x
ist überhaupt nicht seltsam: Konventionell bedeutet es etwas "Privates".object
, damit dies Ihre Einstellung tatsächlich stopptobj.x
. In einer Klasse im alten Stil können Sie tatsächlich noch festlegenobj.x
, mit ziemlich unerwarteten Ergebnissen.Antworten:
Im Allgemeinen sollten Python-Programme unter der Annahme geschrieben werden, dass alle Benutzer Erwachsenen zustimmen und daher dafür verantwortlich sind, die Dinge selbst korrekt zu verwenden. In den seltenen Fällen, in denen es einfach nicht sinnvoll ist, ein Attribut einstellbar zu machen (z. B. einen abgeleiteten Wert oder einen aus einer statischen Datenquelle gelesenen Wert), ist die Eigenschaft "Nur Getter" im Allgemeinen das bevorzugte Muster.
quelle
Nur meine zwei Cent, Silas Ray ist auf dem richtigen Weg, aber ich wollte ein Beispiel hinzufügen. ;-);
Python ist eine typsichere Sprache und daher müssen Sie den Benutzern Ihres Codes immer vertrauen, um den Code wie eine vernünftige (vernünftige) Person zu verwenden.
Gemäß PEP 8 :
Um eine schreibgeschützte Eigenschaft in einer Klasse zu haben, die Sie verwenden können, müssen Sie von der
@property
Dekoration erben,object
wenn Sie dies tun, um die Klassen im neuen Stil zu verwenden.Beispiel:
quelle
self.__a = []
Sie dies beispielsweise noch tun können, funktionierta.a.append('anything')
es.Hier ist ein Weg, um die Annahme zu vermeiden, dass
Bitte beachten Sie mein Update unten
Verwenden
@property
, ist sehr ausführlich, zB:Verwenden von
Mit Ausnahme des letzten ist es eine Konvention. Wenn Sie sich wirklich anstrengen, können Sie dennoch auf Variablen mit doppeltem Unterstrich zugreifen.
Also, was machen wir? Geben wir es auf, schreibgeschützte Eigenschaften in Python zu haben?
Erblicken!
read_only_properties
Dekorateur zur Rettung!Du fragst:
Ich bin froh, dass Sie gefragt haben, hier ist die Quelle für read_only_properties :
aktualisieren
Ich hätte nie gedacht, dass diese Antwort so viel Aufmerksamkeit erhält. Überraschenderweise schon. Dies ermutigte mich, ein Paket zu erstellen, das Sie verwenden können.
in Ihrer Python-Shell:
quelle
if..elif..else
Block könnte einfachif name in attrs and name in self.__dict__: raise Attr...
ohnepass
erforderlich sein. Problem 1: Auf diese Weise dekorierte Klassen erhalten alle eine identische__name__
, und die Zeichenfolgendarstellung ihres Typs wird ebenfalls homogenisiert. Problem 2: Diese Dekoration überschreibt jeden Brauch__setattr__
. Problem 3: Benutzer können dies mit besiegendel MyClass.__setattr__
.object.__setattr__(f, 'forbidden', 42)
. Ich sehe nicht, welcheread_only_properties
Adds nicht durch den doppelten Unterstrichnamen Mangling behandelt werden.Hier ist ein etwas anderer Ansatz für schreibgeschützte Eigenschaften, die vielleicht als einmal beschreibbare Eigenschaften bezeichnet werden sollten, da sie initialisiert werden müssen, nicht wahr? Für die Paranoiden unter uns, die sich Sorgen machen, Eigenschaften durch direkten Zugriff auf das Wörterbuch des Objekts ändern zu können, habe ich "extreme" Namensverknüpfung eingeführt:
quelle
dict_name
stattdessen entstellen , wird beispielsweisedict_name = "_spam_" + name
die Abhängigkeit von entferntuuid4
und das Debuggen wird erheblich vereinfacht.p.__dict__['_spam_x'] = 5
, den Wert von zu ändernp.x
, so dass dies nicht ausreicht, um Namen zu entstellen.Ich bin mit den beiden vorherigen Antworten zum Erstellen schreibgeschützter Eigenschaften unzufrieden, da mit der ersten Lösung das schreibgeschützte Attribut gelöscht und dann festgelegt werden kann und das __dict__ nicht blockiert wird. Die zweite Lösung könnte mit Tests umgangen werden: Finden Sie den Wert, der dem entspricht, den Sie auf zwei festgelegt haben, und ändern Sie ihn schließlich.
Nun zum Code.
Es macht keinen Sinn, schreibgeschützte Attribute zu erstellen, es sei denn, Sie schreiben Bibliothekscode, Code, der als Code zur Verbesserung ihrer Programme an andere verteilt wird, und keinen Code für andere Zwecke wie die App-Entwicklung. Das __dict__ -Problem ist gelöst, da das __dict__ jetzt vom unveränderlichen Typ ist. MappingProxyType ist. , sodass Attribute nicht über __dict__ geändert werden können. Das Festlegen oder Löschen von __dict__ ist ebenfalls blockiert. Die einzige Möglichkeit, schreibgeschützte Eigenschaften zu ändern, besteht darin, die Methoden der Klasse selbst zu ändern.
Obwohl ich glaube, dass meine Lösung besser ist als die beiden vorherigen, könnte sie verbessert werden. Dies sind die Schwächen dieses Codes:
a) Erlaubt nicht das Hinzufügen zu einer Methode in einer Unterklasse, die ein schreibgeschütztes Attribut setzt oder löscht. Eine in einer Unterklasse definierte Methode kann automatisch nicht auf ein schreibgeschütztes Attribut zugreifen, selbst wenn die Version der Methode der Oberklasse aufgerufen wird.
b) Die schreibgeschützten Methoden der Klasse können geändert werden, um die schreibgeschützten Einschränkungen aufzuheben.
Ohne die Bearbeitung der Klasse ist es jedoch nicht möglich, ein schreibgeschütztes Attribut festzulegen oder zu löschen. Dies hängt nicht von Namenskonventionen ab, was gut ist, da Python nicht so konsistent mit Namenskonventionen ist. Auf diese Weise können schreibgeschützte Attribute erstellt werden, die nicht mit ausgeblendeten Lücken geändert werden können, ohne die Klasse selbst zu bearbeiten. Listen Sie einfach die Attribute auf, die schreibgeschützt sein sollen, wenn Sie den Dekorateur als Argumente aufrufen, und sie werden schreibgeschützt.
Dank an Brices Antwort in Wie erhalte ich den Namen der Anruferklasse in einer Funktion einer anderen Klasse in Python? zum Abrufen der Aufruferklassen und -methoden.
quelle
object.__setattr__(pfi, 'readonly', 'foobar')
bricht diese Lösung, ohne die Klasse selbst zu bearbeiten.Beachten Sie, dass Instanzmethoden auch Attribute (der Klasse) sind und dass Sie sie auf Klassen- oder Instanzebene festlegen können, wenn Sie wirklich ein Badass sein möchten. Oder dass Sie eine Klassenvariable festlegen (die auch ein Attribut der Klasse ist), bei der praktische schreibgeschützte Eigenschaften nicht sofort funktionieren. Ich versuche zu sagen, dass das Problem des "schreibgeschützten Attributs" tatsächlich allgemeiner ist, als es normalerweise angenommen wird. Glücklicherweise gibt es konventionelle Erwartungen bei der Arbeit, die so stark sind, dass sie uns für diese anderen Fälle blind machen (schließlich ist fast alles eine Art Attribut in Python).
Aufbauend auf diesen Erwartungen denke ich, dass der allgemeinste und leichteste Ansatz darin besteht, die Konvention zu übernehmen, dass "öffentliche" Attribute (kein führender Unterstrich) schreibgeschützt sind, es sei denn, dies wird ausdrücklich als beschreibbar dokumentiert. Dies setzt die übliche Erwartung voraus, dass Methoden nicht gepatcht werden und Klassenvariablen, die Instanzstandards angeben, besser sind, geschweige denn. Wenn Sie sich in Bezug auf ein bestimmtes Attribut wirklich paranoid fühlen, verwenden Sie einen schreibgeschützten Deskriptor als letzte Ressourcenmaßnahme.
quelle
Während ich den Klassendekorator von Oz123 mag, können Sie auch Folgendes tun, bei dem ein expliziter Klassenumbruch und __new__ mit einer Factory-Methode verwendet werden, die die Klasse innerhalb eines Abschlusses zurückgibt:
quelle
Das ist meine Problemumgehung.
quelle
Jemand erwähnte die Verwendung eines Proxy-Objekts. Ich habe kein Beispiel dafür gesehen und es am Ende [schlecht] ausprobiert.
/! \ Bitte bevorzugen Sie nach Möglichkeit Klassendefinitionen und Klassenkonstruktoren
Dieser Code wird effektiv neu geschrieben
class.__new__
(Klassenkonstruktor), außer in jeder Hinsicht schlechter. Sparen Sie sich den Schmerz und verwenden Sie dieses Muster nicht, wenn Sie können.quelle
Ich weiß, dass ich diesen Thread von den Toten zurückbringe, aber ich habe mir überlegt, wie man eine Eigenschaft schreibgeschützt macht, und nachdem ich dieses Thema gefunden habe, war ich mit den bereits geteilten Lösungen nicht zufrieden.
Kehren Sie also zur ursprünglichen Frage zurück, wenn Sie mit diesem Code beginnen:
Und wenn Sie X schreibgeschützt machen möchten, können Sie einfach hinzufügen:
Wenn Sie dann Folgendes ausführen:
quelle
AttributeError('can't set attribute')