Ich habe eine Klasse mit zwei Klassenmethoden (unter Verwendung der Funktion classmethod ()) zum Abrufen und Festlegen einer im Wesentlichen statischen Variablen. Ich habe versucht, die Eigenschaft property () mit diesen zu verwenden, aber es führt zu einem Fehler. Ich konnte den Fehler im Interpreter wie folgt reproduzieren:
class Foo(object):
_var = 5
@classmethod
def getvar(cls):
return cls._var
@classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
Ich kann die Klassenmethoden demonstrieren, aber sie funktionieren nicht als Eigenschaften:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
Ist es möglich, die Eigenschaft property () mit mit Klassenmethoden dekorierten Funktionen zu verwenden?
class Foo(metaclass=...)
Syntax definieren.Beim Lesen der Python 2.2- Versionshinweise finde ich Folgendes.
HINWEIS: Die folgende Methode funktioniert nicht für Setter, sondern nur für Getter.
Daher glaube ich, dass die vorgeschriebene Lösung darin besteht, eine ClassProperty als Unterklasse von Eigenschaften zu erstellen.
Die Setter funktionieren jedoch nicht wirklich:
foo._var
unverändert ist, haben Sie die Eigenschaft einfach mit einem neuen Wert überschrieben.Sie können auch
ClassProperty
als Dekorateur verwenden:quelle
self.fget(owner)
die Notwendigkeit verwenden und entfernen müssen, überhaupt eine zu verwenden@classmethod
? (das ist , wasclassmethod
ist , zu übersetzen ,.__get__(instance, owner)(*args, **kwargs)
umfunction(owner, *args, **kwargs)
Anrufe über einen Vermittler, Eigenschaften haben die Vermittler nicht brauchen).foo.var = 3
Zuweisung die Eigenschaft nicht tatsächlich durchläuft , sondern stattdessen einfach das Eigenschaftsobjektfoo
durch eine Ganzzahl ersetzt hat. Wenn Sieassert isinstance(foo.__dict__['var'], ClassProperty)
zwischen Ihren Zusicherungen Aufrufe hinzugefügt haben, wird dieser nach derfoo.var = 3
Ausführung fehlschlagen .instance.attr
,instance.attr = value
unddel instance.attr
wird alle bind der Deskriptor gefunden auftype(instance)
, aber währendclassobj.attr
bindet,classobj.attr = value
unddel classobj.attr
sie nicht und stattdessen ersetzen oder das Descriptor - Objekt selbst löschen). Sie benötigen eine Metaklasse, um das Festlegen und Löschen zu unterstützen (das Klassenobjekt wird zur Instanz und die Metaklasse zum Typ).Ich hoffe, dieser
@classproperty
absolut einfache, schreibgeschützte Dekorateur würde jemandem helfen, der nach Klasseneigenschaften sucht.quelle
class D(C): x = 2; assert D.x == 2
.format
wie"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
x
Zugriff durch10
. Ich mag diesen Ansatz, weil er ordentlich und einfach ist, aber wie ein__set__
, das ein erhöhtValueError
, um ein Überschreiben zu verhindern.Nein.
Eine Klassenmethode ist jedoch einfach eine gebundene Methode (eine Teilfunktion) für eine Klasse, auf die über Instanzen dieser Klasse zugegriffen werden kann.
Da die Instanz eine Funktion der Klasse ist und Sie die Klasse von der Instanz ableiten können, können Sie von einer Klasseneigenschaft das gewünschte Verhalten erhalten
property
:Dieser Code kann zum Testen verwendet werden - er sollte ohne Fehler bestehen:
Und beachten Sie, dass wir überhaupt keine Metaklassen benötigten - und Sie sowieso nicht direkt über die Instanzen ihrer Klassen auf eine Metaklasse zugreifen.
einen
@classproperty
Dekorateur schreibenSie können einen
classproperty
Dekorator in nur wenigen Codezeilen durch Unterklassen erstellenproperty
(es ist in C implementiert, aber Sie können hier gleichwertiges Python sehen ):Behandeln Sie den Dekorateur dann so, als wäre es eine Klassenmethode kombiniert mit einer Eigenschaft:
Und dieser Code sollte fehlerfrei funktionieren:
Aber ich bin mir nicht sicher, wie gut das beraten wäre. Eine alte Mailingliste Artikel schlägt vor , es nicht funktionieren sollte.
Damit die Eigenschaft für die Klasse funktioniert:
Der Nachteil des oben Gesagten ist, dass auf die "Klasseneigenschaft" von der Klasse aus nicht zugegriffen werden kann, da sie einfach den Datendeskriptor aus der Klasse überschreiben würde
__dict__
.Wir können dies jedoch mit einer in der Metaklasse definierten Eigenschaft überschreiben
__dict__
. Beispielsweise:Und dann könnte eine Klasseninstanz der Metaklasse eine Eigenschaft haben, die nach dem bereits in den vorherigen Abschnitten beschriebenen Prinzip auf die Eigenschaft der Klasse zugreift:
Und jetzt sehen wir beide die Instanz
und die Klasse
Zugriff auf die Klasseneigenschaft haben.
quelle
Python 3!
Alte Frage, viele Ansichten, die dringend einen One-True-Python-3-Weg benötigen.
Zum Glück ist es mit dem
metaclass
Kwarg einfach :Dann,
>>> Foo.var
quelle
Foo
ist eine Instanz seiner Metaklasse und@property
kann für seine Methoden genauso verwendet werden wie für Instanzen vonFoo
.Foo.__new__
. An diesem Punkt kann es sich jedoch lohnen, stattdessen entweder getattribute zu verwenden oder zu hinterfragen, ob das Vorgeben einer Sprachfunktion wirklich der Ansatz ist, den Sie überhaupt verfolgen möchten.Es gibt keine vernünftige Möglichkeit, dieses "Klasseneigenschaft" -System in Python zum Laufen zu bringen.
Hier ist ein unvernünftiger Weg, damit es funktioniert. Sie können es mit zunehmender Menge an Metaklassen-Magie nahtloser machen.
Der Knotenpunkt des Problems ist, dass Eigenschaften das sind, was Python "Deskriptoren" nennt. Es gibt keine kurze und einfache Möglichkeit zu erklären, wie diese Art der Metaprogrammierung funktioniert, daher muss ich Sie auf das Deskriptor-Howto verweisen .
Sie müssen diese Art von Dingen nur verstehen, wenn Sie ein ziemlich fortgeschrittenes Framework implementieren. Wie eine transparente Objektpersistenz oder ein RPC-System oder eine Art domänenspezifische Sprache.
In einem Kommentar zu einer früheren Antwort sagen Sie jedoch, dass Sie
Mir scheint, was Sie wirklich wollen, ist ein Observer- Designmuster.
quelle
Das Festlegen nur für die Meta-Klasse hilft nicht, wenn Sie über ein instanziiertes Objekt auf die Klasseneigenschaft zugreifen möchten. In diesem Fall müssen Sie auch eine normale Eigenschaft für das Objekt installieren (die an die Klasseneigenschaft gesendet wird). Ich denke, das Folgende ist etwas klarer:
quelle
Eine halbe Lösung, __set__ für die Klasse, funktioniert immer noch nicht. Die Lösung ist eine benutzerdefinierte Eigenschaftsklasse, die sowohl eine Eigenschaft als auch eine statische Methode implementiert
quelle
Haben Sie Zugriff auf mindestens eine Instanz der Klasse? Ich kann mir dann einen Weg vorstellen, es zu tun:
quelle
Probieren Sie es aus, es erledigt den Job, ohne viel vorhandenen Code ändern / hinzufügen zu müssen.
Die
property
Funktion benötigt zweicallable
Argumente. Geben Sie ihnen Lambda-Wrapper (die die Instanz als erstes Argument übergeben) und alles ist gut.quelle
Hier ist eine Lösung, die sowohl für den Zugriff über die Klasse als auch für den Zugriff über eine Instanz funktionieren sollte, die eine Metaklasse verwendet.
Dies funktioniert auch mit einem in der Metaklasse definierten Setter.
quelle
Nachdem ich verschiedene Orte durchsucht hatte, fand ich eine Methode, um eine Klasseneigenschaft zu definieren, die mit Python 2 und 3 gültig ist.
Hoffe das kann jemandem helfen :)
quelle
Hier ist mein Vorschlag. Verwenden Sie keine Klassenmethoden.
Ernsthaft.
Was ist in diesem Fall der Grund für die Verwendung von Klassenmethoden? Warum nicht ein gewöhnliches Objekt einer gewöhnlichen Klasse haben?
Wenn Sie einfach den Wert ändern möchten, ist eine Eigenschaft nicht wirklich sehr hilfreich, oder? Legen Sie einfach den Attributwert fest und fertig.
Eine Eigenschaft sollte nur verwendet werden, wenn etwas zu verbergen ist - etwas, das sich in einer zukünftigen Implementierung ändern könnte.
Vielleicht ist Ihr Beispiel sehr reduziert, und Sie haben eine höllische Berechnung aufgegeben. Es sieht jedoch nicht so aus, als würde die Immobilie einen erheblichen Mehrwert bieten.
Die von Java beeinflussten "Datenschutz" -Techniken (in Python Attributnamen, die mit _ beginnen) sind nicht wirklich hilfreich. Privat von wem? Der private Punkt ist ein wenig nebulös, wenn Sie die Quelle haben (wie in Python).
Die von Java beeinflussten Getter und Setter im EJB-Stil (in Python häufig als Eigenschaften verwendet) dienen dazu, die primitive Selbstbeobachtung von Java zu erleichtern und die Musterung mit dem statischen Sprachcompiler zu bestehen. All diese Getter und Setter sind in Python nicht so hilfreich.
quelle