Apakah mungkin untuk menggunakan fungsi properti () dengan fungsi yang didekorasi dengan metode kelas?
Tidak.
Namun, metode kelas hanyalah metode terikat (fungsi parsial) pada kelas yang dapat diakses dari instance kelas itu.
Karena instance adalah fungsi dari kelas dan Anda bisa mendapatkan kelas dari instance, Anda bisa mendapatkan perilaku apa pun yang diinginkan yang mungkin Anda inginkan dari properti kelas dengan 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
Kode ini dapat digunakan untuk menguji - kode harus lulus tanpa menimbulkan kesalahan:
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')
Dan perhatikan bahwa kita sama sekali tidak membutuhkan metaclasses - dan Anda tidak secara langsung mengakses metaclass melalui instance kelasnya.
menulis @classproperty
dekorator
Anda sebenarnya dapat membuat classproperty
dekorator hanya dalam beberapa baris kode dengan mensubclassing property
(ini diterapkan dalam C, tetapi Anda dapat melihat Python yang setara di sini ):
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))
Kemudian perlakukan dekorator seolah-olah itu adalah metode kelas yang dikombinasikan dengan properti:
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
Dan kode ini seharusnya bekerja tanpa kesalahan:
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()
Tapi saya tidak yakin seberapa baik ini disarankan. Artikel milis lama menyarankan itu tidak akan berfungsi.
Membuat properti bekerja di kelas:
Kelemahan dari di atas adalah bahwa "properti kelas" tidak dapat diakses dari kelas, karena itu hanya akan menimpa deskriptor data dari kelas __dict__
.
Namun, kita bisa menimpanya dengan properti yang didefinisikan dalam metaclass __dict__
. Sebagai contoh:
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
Dan kemudian instance kelas dari metaclass dapat memiliki properti yang mengakses properti kelas menggunakan prinsip yang sudah ditunjukkan di bagian sebelumnya:
class FooClassProperty(metaclass=MetaWithFooClassProperty):
@property
def foo(self):
"""access the class's property"""
return type(self).foo
Dan sekarang kita melihat keduanya
>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>
dan kelas
>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>
memiliki akses ke properti kelas.