เป็นไปได้ไหมที่จะใช้คุณสมบัติ () กับฟังก์ชั่นการตกแต่งแบบชั้นเรียน?
เลขที่
อย่างไรก็ตามคลาสของเมธอดเป็นเพียงเมธอดที่ถูกผูกไว้ (ฟังก์ชันบางส่วน) ในคลาสที่สามารถเข้าถึงได้จากอินสแตนซ์ของคลาสนั้น
เนื่องจากอินสแตนซ์เป็นฟังก์ชันของคลาสและคุณสามารถสืบทอดคลาสจากอินสแตนซ์ได้คุณสามารถรับพฤติกรรมตามที่คุณต้องการจากคลาสคุณสมบัติด้วย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
รหัสนี้สามารถใช้ในการทดสอบ - ควรผ่านโดยไม่มีข้อผิดพลาด:
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')
และโปรดทราบว่าเราไม่ต้องการ metaclasses เลยและคุณไม่สามารถเข้าถึง metaclass โดยตรงผ่านอินสแตนซ์ของคลาส
เขียน@classproperty
มัณฑนากร
คุณสามารถสร้างclassproperty
มัณฑนากรได้ในโค้ดเพียงไม่กี่บรรทัดโดย subclassing property
(มันถูกใช้ใน C แต่คุณสามารถเห็น Python ที่เทียบเท่าได้ที่นี่ ):
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))
จากนั้นให้ถือว่ามัณฑนากรราวกับว่ามันเป็น classmethod รวมกับคุณสมบัติ:
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
และรหัสนี้ควรทำงานโดยไม่มีข้อผิดพลาด:
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()
แต่ฉันไม่แน่ใจว่าจะเป็นเช่นไร บทความรายชื่อผู้รับจดหมายเก่าแนะนำว่าไม่ควรใช้งาน
การรับคุณสมบัติเพื่อทำงานกับคลาส:
ข้อเสียของการดังกล่าวข้างต้นก็คือว่า "ทรัพย์สินคลาส" __dict__
ไม่สามารถเข้าถึงได้จากชั้นเรียนเพราะมันก็จะเขียนทับให้คำอธิบายถึงข้อมูลจากชั้นเรียน
อย่างไรก็ตามเราสามารถแทนที่นี้กับสถานที่ให้บริการที่กำหนดไว้ใน __dict__
metaclass ตัวอย่างเช่น:
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
จากนั้นคลาสอินสแตนซ์ของ metaclass อาจมีคุณสมบัติที่เข้าถึงคุณสมบัติของคลาสโดยใช้หลักการที่แสดงไว้แล้วในส่วนก่อนหน้านี้:
class FooClassProperty(metaclass=MetaWithFooClassProperty):
@property
def foo(self):
"""access the class's property"""
return type(self).foo
และตอนนี้เราเห็นทั้งสองกรณี
>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>
และชั้นเรียน
>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>
มีการเข้าถึงคุณสมบัติระดับ