Ist es möglich, die Eigenschaft property () mit mit Klassenmethoden dekorierten Funktionen zu verwenden?
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
:
class Example(object):
_class_property = None
@property
def class_property(self):
return self._class_property
@class_property.setter
def class_property(self, value):
type(self)._class_property = value
@class_property.deleter
def class_property(self):
del type(self)._class_property
Dieser Code kann zum Testen verwendet werden - er sollte ohne Fehler bestehen:
ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')
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 schreiben
Sie können einen classproperty
Dekorator in nur wenigen Codezeilen durch Unterklassen erstellen property
(es ist in C implementiert, aber Sie können hier gleichwertiges Python sehen ):
class classproperty(property):
def __get__(self, obj, objtype=None):
return super(classproperty, self).__get__(objtype)
def __set__(self, obj, value):
super(classproperty, self).__set__(type(obj), value)
def __delete__(self, obj):
super(classproperty, self).__delete__(type(obj))
Behandeln Sie den Dekorateur dann so, als wäre es eine Klassenmethode kombiniert mit einer Eigenschaft:
class Foo(object):
_bar = 5
@classproperty
def bar(cls):
"""this is the bar attribute - each subclass of Foo gets its own.
Lookups should follow the method resolution order.
"""
return cls._bar
@bar.setter
def bar(cls, value):
cls._bar = value
@bar.deleter
def bar(cls):
del cls._bar
Und dieser Code sollte fehlerfrei funktionieren:
def main():
f = Foo()
print(f.bar)
f.bar = 4
print(f.bar)
del f.bar
try:
f.bar
except AttributeError:
pass
else:
raise RuntimeError('f.bar must have worked - inconceivable!')
help(f) # includes the Foo.bar help.
f.bar = 5
class Bar(Foo):
"a subclass of Foo, nothing more"
help(Bar) # includes the Foo.bar help!
b = Bar()
b.bar = 'baz'
print(b.bar) # prints baz
del b.bar
print(b.bar) # prints 5 - looked up from Foo!
if __name__ == '__main__':
main()
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:
class MetaWithFooClassProperty(type):
@property
def foo(cls):
"""The foo property is a function of the class -
in this case, the trivial case of the identity function.
"""
return cls
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:
class FooClassProperty(metaclass=MetaWithFooClassProperty):
@property
def foo(self):
"""access the class's property"""
return type(self).foo
Und jetzt sehen wir beide die Instanz
>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>
und die Klasse
>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>
Zugriff auf die Klasseneigenschaft haben.