Ich würde gerne verstehen, wie die eingebaute Funktion ist property
funktioniert. Was mich verwirrt ist, dass property
es auch als Dekorateur verwendet werden kann, aber es braucht nur Argumente, wenn es als eingebaute Funktion verwendet wird und nicht, wenn es als Dekorateur verwendet wird.
Dieses Beispiel stammt aus der Dokumentation :
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
property
Die Argumente sind getx
:setx
, delx
und ein doc - String.
Im folgenden Code property
wird als Dekorateur verwendet. Das Objekt davon ist die x
Funktion, aber im obigen Code ist in den Argumenten kein Platz für eine Objektfunktion.
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Und wie entstehen die x.setter
und x.deleter
Dekorateure? Ich bin verwirrt.
property
ist eigentlich eine Klasse (keine Funktion), obwohl sie die__init__()
Methode wahrscheinlich aufruft , wenn Sie ein Objekt erstellen. Die Verwendunghelp(property)
vom Terminal aus ist aufschlussreich.help
ist aus irgendeinem Grund auch eine Klasse.Antworten:
Die
property()
Funktion gibt ein spezielles Deskriptorobjekt zurück :Es ist dieses Objekt, das zusätzliche Methoden hat:
Diese wirken als Dekorateure zu . Sie geben ein neues Eigenschaftsobjekt zurück:
Das ist eine Kopie des alten Objekts, wobei jedoch eine der Funktionen ersetzt wurde.
Denken Sie daran, dass die
@decorator
Syntax nur syntaktischer Zucker ist. die Syntax:bedeutet wirklich das Gleiche wie
daher wird
foo
die Funktion ersetzt durchproperty(foo)
, was wir oben gesehen haben, ist ein spezielles Objekt. Wenn Sie dann verwenden@foo.setter()
, nennen Sie dasproperty().setter
Sie die oben gezeigte Methode auf, die eine neue Kopie der Eigenschaft zurückgibt, diesmal jedoch, wobei die Setter-Funktion durch die dekorierte Methode ersetzt wird.In der folgenden Sequenz wird mithilfe dieser Decorator-Methoden auch eine Full-On-Eigenschaft erstellt.
Zuerst erstellen wir einige Funktionen und ein
property
Objekt mit nur einem Getter:Als nächstes verwenden wir die
.setter()
Methode, um einen Setter hinzuzufügen:Zuletzt fügen wir mit der
.deleter()
Methode einen Deleter hinzu :Last but dest nicht das
property
Objekt wirkt als Descriptor - Objekt , so hat es.__get__()
,.__set__()
und.__delete__()
Methoden in dem Instanzattribut einzuzuhaken bekommen, das Setzen und Löschen von :Das Descriptor Howto enthält eine reine Python-Beispielimplementierung des
property()
Typs:quelle
Foo.prop = prop
SieFoo().prop = 5; pront Foo().prop; del Foo().prop
mit dem gewünschten Ergebnis fertig werden können.type()
als Zugriff auf dunder Attribute und Methoden, die von den Standardfunktionen und Operatoren als Erweiterungspunkte verwendet werden sollen.@human.name.getter
dasproperty
Objekt an Ort und Stellehuman.name
geändert wird, anstatt ein neues zurückzugeben, wird das Attribut geändert, wodurch sich das Verhalten dieser Oberklasse ändert.Die Dokumentation besagt, dass dies nur eine Verknüpfung zum Erstellen schreibgeschützter Eigenschaften ist. Damit
ist äquivalent zu
quelle
@property
in seiner Klasse als Dekorateur gearbeitet hatte.Hier ist ein minimales Beispiel für
@property
die Implementierung:Ansonsten
word
bleibt eine Methode anstelle einer Eigenschaft.quelle
self.word = my_word
- was dann genauso funktionieren würdeprint( Thing('ok').word ) = 'ok'
Thing('ok').word
die Funktion zur Laufzeit intern aufruft?Der erste Teil ist einfach:
ist das gleiche wie
property
mit nur einem Getter.Der nächste Schritt wäre, diese Eigenschaft mit einem Setter und einem Deleter zu erweitern. Und dies geschieht mit den entsprechenden Methoden:
Gibt eine neue Eigenschaft zurück, die alles vom alten
x
und vom angegebenen Setter erbt .x.deleter
funktioniert genauso.quelle
Folgendes:
Ist das gleiche wie:
Ist das gleiche wie:
Ist das gleiche wie:
Welches ist das gleiche wie:
quelle
Im Folgenden finden Sie ein weiteres Beispiel, wie Sie
@property
helfen können, wenn Sie den von hier übernommenen Code umgestalten müssen (ich fasse ihn unten nur zusammen):Stellen Sie sich vor, Sie haben eine Klasse
Money
wie diese erstellt:und ein Benutzer erstellt abhängig von dieser Klasse eine Bibliothek, in der er z
Nun nehmen wir an , Sie entscheiden , Ihre Änderungen
Money
Klasse und loszuwerden, die erhaltendollars
undcents
Attribute , sondern entscheiden, nur den Gesamtbetrag von Cent zu verfolgen:Wenn der oben genannte Benutzer nun versucht, seine Bibliothek wie zuvor auszuführen
es wird zu einem Fehler führen
Das bedeutet, dass jetzt jeder, der sich auf Ihre ursprüngliche
Money
Klasse verlässt , alle Codezeilen ändern muss, wodollars
und wo siecents
verwendet werden, was sehr schmerzhaft sein kann ... Wie könnte dies vermieden werden? Mit@property
!Das ist wie:
wenn wir jetzt aus unserer Bibliothek anrufen
es wird wie erwartet funktionieren und wir mussten keine einzige Codezeile in unserer Bibliothek ändern! Tatsächlich müssten wir nicht einmal wissen, dass sich die Bibliothek, von der wir abhängig sind, geändert hat.
Auch das
setter
funktioniert gut:Sie können
@property
auch in abstrakten Klassen verwenden; Ich gebe ein minimales Beispiel hier .quelle
self.dollar = dollars
? Wir haben so viel mit @property gemacht, aber es scheint, dass keine Extraktionsfunktion hinzugefügt wurde.Ich habe alle Beiträge hier gelesen und festgestellt, dass wir möglicherweise ein Beispiel aus dem wirklichen Leben brauchen. Warum haben wir eigentlich @property? Stellen Sie sich also eine Flask-App vor, in der Sie das Authentifizierungssystem verwenden. Sie deklarieren einen Modellbenutzer in
models.py
:In diesem Code haben wir das Attribut "versteckt"
password
indem es@property
die Bestätigung auslöstAttributeError
, wenn Sie versuchen, direkt darauf zuzugreifen, während wir @ property.setter verwendet haben, um die tatsächliche Instanzvariable festzulegenpassword_hash
.Jetzt in
auth/views.py
können wir einen Benutzer instanziieren mit:Hinweisattribut
password
, das aus einem Registrierungsformular stammt, wenn ein Benutzer das Formular ausfüllt. Die Passwortbestätigung erfolgt am Frontend mitEqualTo('password', message='Passwords must match')
(falls Sie sich fragen, es sich jedoch um ein anderes themenbezogenes Flask-Formular handelt).Ich hoffe, dieses Beispiel wird nützlich sein
quelle
Dieser Punkt wurde von vielen Leuten dort oben geklärt, aber hier ist ein direkter Punkt, den ich gesucht habe. Dies ist meiner Meinung nach wichtig, um mit dem @ property-Dekorateur zu beginnen. z.B:-
Der Aufruf der Funktion "get_config ()" funktioniert folgendermaßen.
Wenn Sie bemerken, dass ich keine "()" Klammern zum Aufrufen der Funktion verwendet habe. Dies ist die grundlegende Sache, nach der ich nach dem @ property-Dekorateur gesucht habe. Damit Sie Ihre Funktion wie eine Variable verwenden können.
quelle
Beginnen wir mit Python-Dekoratoren.
Ein Python-Dekorator ist eine Funktion, mit der Sie einer bereits definierten Funktion einige zusätzliche Funktionen hinzufügen können.
In Python ist alles ein Objekt. Funktionen in Python sind erstklassige Objekte, dh sie können von einer Variablen referenziert, in die Listen aufgenommen, als Argumente an eine andere Funktion usw. übergeben werden.
Betrachten Sie das folgende Code-Snippet.
Hier können wir sagen, dass die Decorator-Funktion unsere say_hello-Funktion geändert und einige zusätzliche Codezeilen hinzugefügt hat.
Python-Syntax für Dekorateur
Lassen Sie uns alles abschließen als mit einem Fallszenario, aber vorher sprechen wir über einige Hoppla-Prinzipien.
Getter und Setter werden in vielen objektorientierten Programmiersprachen verwendet, um das Prinzip der Datenkapselung sicherzustellen (wird als Bündelung von Daten mit den Methoden angesehen, die mit diesen Daten arbeiten).
Diese Methoden sind natürlich der Getter zum Abrufen der Daten und der Setter zum Ändern der Daten.
Nach diesem Prinzip werden die Attribute einer Klasse privatisiert, um sie zu verbergen und vor anderem Code zu schützen.
Ja, @property ist im Grunde ein pythonische Methode, um Getter und Setter zu verwenden.
Python hat ein großartiges Konzept namens Eigenschaft, das das Leben eines objektorientierten Programmierers viel einfacher macht.
Nehmen wir an, Sie entscheiden sich für eine Klasse, in der die Temperatur in Grad Celsius gespeichert werden kann.
Refactored Code, hier ist, wie wir es mit Eigentum erreicht haben könnten.
In Python ist property () eine integrierte Funktion, die ein Eigenschaftsobjekt erstellt und zurückgibt.
Ein Eigenschaftsobjekt verfügt über drei Methoden: getter (), setter () und delete ().
Hier,
hätte aufgeschlüsselt werden können als,
Zu beachtender Punkt:
Jetzt können Sie durch Schreiben auf den Temperaturwert zugreifen.
Wir können weiter gehen und die Namen get_temperature und set_temperature nicht definieren, da sie unnötig sind und den Klassennamensraum verschmutzen.
Der pythonische Weg , um mit dem oben genannten Problem umzugehen, ist die Verwendung von @property .
Zu beachtende Punkte -
Wie Sie sehen können, ist der Code definitiv weniger elegant.
Lassen Sie uns nun über ein reales praktisches Szenario sprechen.
Angenommen, Sie haben eine Klasse wie folgt entworfen:
Nehmen wir nun weiter an, dass unsere Klasse bei Kunden beliebt wurde und sie sie in ihren Programmen verwendeten. Sie haben dem Objekt alle Arten von Aufgaben zugewiesen.
Und eines schicksalhaften Tages kam ein vertrauenswürdiger Kunde zu uns und schlug vor, dass "x" ein Wert zwischen 0 und 1000 sein muss. Dies ist wirklich ein schreckliches Szenario!
Aufgrund von Eigenschaften ist es einfach: Wir erstellen eine Eigenschaftsversion von "x".
Das ist großartig, nicht wahr: Sie können mit der einfachsten Implementierung beginnen, die Sie sich vorstellen können, und Sie können später auf eine Eigenschaftsversion migrieren, ohne die Benutzeroberfläche ändern zu müssen! Eigenschaften sind also nicht nur ein Ersatz für Getter und Setter!
Sie können diese Implementierung hier überprüfen
quelle
property
ist eine Klasse dahinter@property
Dekorateur.Sie können dies jederzeit überprüfen:
Ich habe das Beispiel von umgeschrieben, um
help(property)
zu zeigen, dass die@property
Syntaxist funktional identisch mit der
property()
Syntax:Wie Sie sehen, gibt es keinen Unterschied, wie wir die Immobilie nutzen.
Zur Beantwortung der Frage wird der
@property
Dekorateur über dieproperty
Klasse implementiert .Die Frage ist also, die
property
Klasse ein wenig zu erklären . Diese Linie:War die Initialisierung. Wir können es so umschreiben:
Die Bedeutung von
fget
,fset
undfdel
:Das nächste Bild zeigt die Drillinge, die wir aus der Klasse haben
property
:__get__
,__set__
Und__delete__
sind dort zu sein , außer Kraft gesetzt . Dies ist die Implementierung des Deskriptormusters in Python.Wir können auch verwenden Eigenschaft
setter
,getter
unddeleter
Methoden , um die Funktion zu Eigentum zu binden. Überprüfen Sie das nächste Beispiel. Die Methodes2
der KlasseC
setzt die Eigenschaft verdoppelt .quelle
Eine Eigenschaft kann auf zwei Arten deklariert werden.
Sie können sich einige Beispiele ansehen, die ich über Eigenschaften in Python geschrieben habe .
quelle
Die beste Erklärung finden Sie hier: Python @Property Explained - Wie und wann? (Vollständige Beispiele) von Selva Prabhakaran | Veröffentlicht am 5. November 2018
Es half mir zu verstehen, WARUM nicht nur WIE.
https://www.machinelearningplus.com/python/python-property/
quelle
Hier ist ein weiteres Beispiel:
Grundsätzlich das gleiche wie im C (Objekt) -Beispiel, außer dass ich stattdessen x verwende ... Ich initialisiere auch nicht in __init - ... nun ja, aber es kann entfernt werden, weil __x als Teil definiert ist der Klasse....
Die Ausgabe ist:
und wenn ich self.x = 1234 in init auskommentiere, lautet die Ausgabe:
und wenn ich in der Getter-Funktion _default = None auf _default = 0 setze (da alle Getter einen Standardwert haben sollten, dieser aber nicht von den Eigenschaftswerten übergeben wird, die ich gesehen habe, können Sie ihn hier definieren, und es ist eigentlich nicht schlecht, weil Sie den Standard einmal definieren und überall verwenden können) dh: def x (self, _default = 0):
Hinweis: Die Getter-Logik dient nur dazu, den Wert von ihm manipulieren zu lassen, um sicherzustellen, dass er von ihm manipuliert wird - dasselbe gilt für die print-Anweisungen ...
Hinweis: Ich bin an Lua gewöhnt und in der Lage, mehr als 10 Helfer dynamisch zu erstellen, wenn ich eine einzelne Funktion aufrufe, und ich habe etwas Ähnliches für Python erstellt, ohne Eigenschaften zu verwenden, und es funktioniert bis zu einem gewissen Grad, aber obwohl die Funktionen zuvor erstellt wurden Bei der Verwendung gibt es manchmal immer noch Probleme, wenn sie vor dem Erstellen aufgerufen werden, was seltsam ist, da sie nicht so codiert sind. Ich bevorzuge die Flexibilität von Lua-Metatabellen und die Tatsache, dass ich tatsächliche Setter / Getter verwenden kann anstatt im Wesentlichen direkt auf eine Variable zuzugreifen ... Ich mag es, wie schnell einige Dinge mit Python erstellt werden können - zum Beispiel GUI-Programme. Obwohl eine, die ich entwerfe, ohne viele zusätzliche Bibliotheken möglicherweise nicht möglich ist - wenn ich sie in AutoHotkey codiere, kann ich direkt auf die benötigten DLL-Aufrufe zugreifen, und das Gleiche kann in Java, C #, C ++,
Hinweis: Die Code-Ausgabe in diesem Forum ist fehlerhaft - ich musste dem ersten Teil des Codes Leerzeichen hinzufügen, damit es funktioniert - beim Kopieren / Einfügen stellen Sie sicher, dass Sie alle Leerzeichen in Tabulatoren konvertieren. Ich verwende Tabulatoren für Python, weil in Bei einer Datei mit 10.000 Zeilen kann die Dateigröße 512 KB bis 1 MB mit Leerzeichen und 100 bis 200 KB mit Tabulatoren betragen, was einem massiven Unterschied in Bezug auf die Dateigröße und einer Verkürzung der Verarbeitungszeit entspricht.
Tabs können auch pro Benutzer angepasst werden. Wenn Sie also 2 Leerzeichen, 4, 8 oder was auch immer bevorzugen, können Sie dies für Entwickler mit Sehbehinderungen tun.
Hinweis: Alle in der Klasse definierten Funktionen werden aufgrund eines Fehlers in der Forensoftware nicht richtig eingerückt. Stellen Sie sicher, dass Sie sie beim Kopieren / Einfügen einrücken
quelle
Eine Bemerkung: Für mich hat Python 2.x
@property
nicht wie angekündigt funktioniert, als ich nicht geerbt habe vonobject
:aber funktionierte wenn:
für Python 3 hat immer funktioniert.
quelle
object
wird , eine Klasse alten Stils ist und Klassen alten Stils das Deskriptorprotokoll nicht unterstützen (wasproperty
implementiert wird, um so zu funktionieren, wie es funktioniert). In Python 3 gibt es keine Klassen im alten Stil mehr. Alle Klassen sind das, was wir in Python 2 als Klassen neuen Stils bezeichnet haben.