Es scheint mir, dass property () bis auf ein wenig syntaktischen Zucker nichts Gutes tut.
Sicher, es ist schön zu können , schreiben , a.b=2
statt a.setB(2)
, aber die Tatsache versteckt , dass ab = 2 nicht eine einfache Zuordnung sieht aus wie ein Rezept für Probleme ist, sei es, weil einige unerwartete Ergebnis kann passieren, wie a.b=2
tatsächlich verursacht a.b
werden 1
. Oder es wird eine Ausnahme ausgelöst. Oder ein Leistungsproblem. Oder einfach nur verwirrend sein.
Können Sie mir ein konkretes Beispiel für eine gute Verwendung geben? (es zu zählen, um problematischen Code zu patchen, zählt nicht ;-)
python
properties
Olamundo
quelle
quelle
__getattr__
/__setattr__
, die weit vor den Eigenschaften liegen), gibt es nicht viel mehr "Java-Leute" (in einer dieser Sprachen, einschließlich C ++! -) kann möglicherweise tun, um die Einkapselung zu erhalten.Antworten:
In Sprachen wie Java, die auf Getter und Setter angewiesen sind, wird von ihnen nicht erwartet, dass sie etwas anderes tun als das, was sie sagen. Es wäre erstaunlich, wenn
x.getB()
sie etwas anderes tun würden, als den aktuellen Wert des logischen Attributs zurückzugebenb
, oder wennx.setB(2)
sie etwas anderes tun würden Für diex.getB()
Rückgabe ist ein geringer interner Arbeitsaufwand erforderlich2
.Es gibt jedoch keine sprachlich auferlegten Garantien für dieses erwartete Verhalten, dh vom Compiler erzwungene Einschränkungen für den Methodenkörper, dessen Namen mit
get
oderset
vielmehr dem gesunden Menschenverstand, den sozialen Konventionen, "Styleguides" und dem Testen überlassen bleiben .Das Verhalten von
x.b
Zugriffen und Zuweisungen wiex.b = 2
in Sprachen, die Eigenschaften haben (eine Reihe von Sprachen, die Python enthalten, aber nicht darauf beschränkt sind), ist genau das gleiche wie für Getter- und Setter-Methoden in z. B. Java: dieselben Erwartungen, der gleiche Mangel an sprachlich erzwungenen Garantien.Der erste Gewinn für Eigenschaften ist die Syntax und Lesbarkeit. Schreiben müssen, z.
x.setB(x.getB() + 1)
anstelle des Offensichtlichen
x.b += 1
schreit nach Rache an den Göttern. In Sprachen, die Eigenschaften unterstützen, gibt es absolut keinen guten Grund, Benutzer der Klasse zu zwingen, die Drehungen einer solchen byzantinischen Boilerplate zu durchlaufen, was die Lesbarkeit ihres Codes ohne jeglichen Vorteil beeinträchtigt.
Insbesondere in Python gibt es einen weiteren großen Vorteil bei der Verwendung von Eigenschaften (oder anderen Deskriptoren) anstelle von Gettern und Setzern: Wenn Sie Ihre Klasse so reorganisieren, dass der zugrunde liegende Setter und Getter nicht mehr benötigt werden, können Sie dies (ohne die Klassen zu beschädigen) veröffentlichte API) eliminieren einfach diese Methoden und die Eigenschaft, die auf ihnen beruht, und machen
b
ein normales "gespeichertes" Attribut derx
Klasse von 'anstatt eines "logischen" Attributs , das erhalten und rechnerisch festgelegt wird.In Python ist es eine wichtige Optimierung, Dinge direkt (wenn möglich) statt über Methoden auszuführen. Durch die systematische Verwendung von Eigenschaften können Sie diese Optimierung durchführen, wann immer dies möglich ist (wobei "normale gespeicherte Attribute" immer direkt verfügbar gemacht werden und nur solche, die beim Zugriff berechnet werden müssen und / oder Einstellung über Methoden und Eigenschaften).
Wenn Sie also Getter und Setter anstelle von Eigenschaften verwenden, ohne die Lesbarkeit des Codes Ihrer Benutzer zu beeinträchtigen, verschwenden Sie auch unentgeltlich Maschinenzyklen (und die Energie, die während dieser Zyklen an ihren Computer fließt ;-), wiederum ohne guten Grund was auch immer.
Ihr einziges Argument gegen Eigenschaften ist z. B., dass "ein externer Benutzer normalerweise keine Nebenwirkungen aufgrund einer Zuweisung erwarten würde"; Sie vermissen jedoch die Tatsache, dass derselbe Benutzer (in einer Sprache wie Java, in der Getter und Setter allgegenwärtig sind) keine (beobachtbaren) "Nebenwirkungen" erwarten würde, wenn er einen Setter aufruft (und noch weniger für einen Getter) ;-). Es sind vernünftige Erwartungen, und es liegt an Ihnen als Klassenautor, zu versuchen, sie zu berücksichtigen - ob Ihr Setter und Getter direkt oder über eine Immobilie verwendet werden, spielt keine Rolle. Wenn Sie Methoden mit wichtigen beobachtbare Nebenwirkungen haben, sie nicht nennen sie
getThis
,setThat
und sie nicht über Eigenschaften verwenden.Die Beschwerde , dass die Eigenschaften „die Umsetzung verstecken“ ist völlig unberechtigt: Die meisten alle des OOP ist über Information Hiding Umsetzung - macht eine Klasse für eine logische Schnittstelle zur Außenwelt zu präsentieren und es intern als beste Umsetzung es kann. Getter und Setter sind genau wie Eigenschaften Werkzeuge für dieses Ziel. Eigenschaften machen es einfach besser (in Sprachen, die sie unterstützen ;-).
quelle
__add__
sich selbst zu ändern und / oder etwas zu tun, das nichts mit Addition zu tun hat - das bedeutet nicht, dass eine Überladung des Bedieners eine schlechte Sache ist, wenn sie geschmackvoll und vernünftig verwendet wird (obwohl Javas Designer stimme nicht zu, da sie es absichtlich aus ihrer Sprache herausgelassen haben! -).Die Idee ist, dass Sie vermeiden müssen, Getter und Setter schreiben zu müssen, bis Sie sie tatsächlich benötigen.
Um zu beginnen, schreiben Sie:
class MyClass(object): def __init__(self): self.myval = 4
Natürlich können Sie jetzt schreiben
myobj.myval = 5
.Aber später entscheiden Sie, dass Sie einen Setter brauchen, da Sie gleichzeitig etwas Kluges tun möchten. Aber Sie möchten nicht den gesamten Code ändern müssen, der Ihre Klasse verwendet - also wickeln Sie den Setter in den
@property
Dekorator ein, und alles funktioniert einfach.quelle
@property
dem Setter / Getter Logik hinzufügten und die Kompatibilität nicht beeinträchtigten. Dies führt absichtlich zu@property
Nebenwirkungen und ist für zukünftige Programmierer mit demselben Code verwirrend.Sie verstecken diese Tatsache jedoch nicht; Diese Tatsache war von Anfang an nie da. Dies ist Python - eine Hochsprache; keine Montage. Nur wenige der darin enthaltenen "einfachen" Anweisungen beschränken sich auf einzelne CPU-Anweisungen. Einfachheit in eine Aufgabe einzulesen bedeutet, Dinge zu lesen, die nicht da sind.
Wenn Sie xb = c sagen, sollten Sie wahrscheinlich nur denken, dass "was auch immer gerade passiert ist, xb sollte jetzt c sein".
quelle
Ein grundlegender Grund ist wirklich einfach, dass es besser aussieht. Es ist mehr pythonisch. Besonders für Bibliotheken. etwas.getValue () sieht weniger gut aus als etwas.Wert
In plone (einem ziemlich großen CMS) hatten Sie früher document.setTitle (), das viele Dinge wie das Speichern des Werts, das erneute Indizieren und so weiter erledigt. Nur document.title = 'etwas' zu tun ist schöner. Sie wissen, dass hinter den Kulissen sowieso viel passiert.
quelle
Sie haben Recht, es ist nur syntaktischer Zucker. Abhängig von Ihrer Definition des problematischen Codes kann es sein, dass es keine gute Verwendung gibt.
Bedenken Sie, dass Sie eine Klasse Foo haben, die in Ihrer Anwendung weit verbreitet ist. Jetzt ist diese Anwendung ziemlich groß geworden und es ist eine Webanwendung, die sehr beliebt geworden ist.
Sie erkennen, dass Foo einen Engpass verursacht. Vielleicht ist es möglich, Foo etwas Caching hinzuzufügen, um es zu beschleunigen. Mit den Eigenschaften können Sie dies tun, ohne Code oder Tests außerhalb von Foo zu ändern.
Ja, das ist natürlich problematischer Code, aber Sie haben gerade eine Menge Geld gespart, um ihn schnell zu beheben.
Was ist, wenn sich Foo in einer Bibliothek befindet, für die Sie Hunderte oder Tausende von Benutzern haben? Nun, Sie haben es sich erspart, ihnen sagen zu müssen, dass sie einen teuren Refactor durchführen sollen, wenn sie auf die neueste Version von Foo upgraden.
Die Versionshinweise enthalten anstelle einer Anleitung zur Absatzportierung ein Lineitem zu Foo.
Erfahrene Python-Programmierer erwarten nicht viel von
a.b=2
anderen alsa.b==2
, aber sie wissen, dass selbst das möglicherweise nicht stimmt. Was in der Klasse passiert, ist ein eigenes Geschäft.quelle
Hier ist ein altes Beispiel von mir. Ich habe eine C-Bibliothek mit Funktionen wie "void dt_setcharge (int atom_handle, int new_charge)" und "int dt_getcharge (int atom_handle)" eingeschlossen. Ich wollte auf Python-Ebene "atom.charge = atom.charge + 1" machen.
Der Dekorateur "Eigentum" macht das einfach. Etwas wie:
class Atom(object): def __init__(self, handle): self.handle = handle def _get_charge(self): return dt_getcharge(self.handle) def _set_charge(self, charge): dt_setcharge(self.handle, charge) charge = property(_get_charge, _set_charge)
Als ich dieses Paket vor 10 Jahren schrieb, musste ich __getattr__ und __setattr__ verwenden, was es möglich machte, aber die Implementierung war viel fehleranfälliger.
class Atom: def __init__(self, handle): self.handle = handle def __getattr__(self, name): if name == "charge": return dt_getcharge(self.handle) raise AttributeError(name) def __setattr__(self, name, value): if name == "charge": dt_setcharge(self.handle, value) else: self.__dict__[name] = value
quelle
Getter und Setter werden für viele Zwecke benötigt und sind sehr nützlich, da sie für den Code transparent sind. Wenn das Objekt Something die Eigenschaft height hat, weisen Sie einen Wert als Something.height = 10 zu. Wenn die Höhe jedoch einen Getter und einen Setter hat, können Sie zu dem Zeitpunkt, zu dem Sie diesen Wert zuweisen, viele Dinge in den Prozeduren tun, z. B. das Validieren eines Min oder Max Wert, wie das Auslösen eines Ereignisses, weil sich die Höhe geändert hat, und das automatische Festlegen anderer Werte in Abhängigkeit vom neuen Höhenwert. Dies kann alles sein, was zum Zeitpunkt der Zuweisung von Something.height-Werten auftreten kann. Denken Sie daran, dass Sie sie in Ihrem Code nicht aufrufen müssen. Sie werden automatisch ausgeführt, sobald Sie den Eigenschaftswert lesen oder schreiben. In gewisser Weise sind sie wie Ereignisprozeduren, wenn der Wert der Eigenschaft X den Wert ändert und wenn der Wert der Eigenschaft X gelesen wird.
quelle