是否可以将 property() 函数与 classmethod 修饰函数一起使用?
没有。
但是,类方法只是类的绑定方法(部分函数),可从该类的实例访问。
由于实例是类的函数,并且您可以从实例派生类,因此您可以使用 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')
请注意,我们根本不需要元类 - 无论如何,您也不能通过其类的实例直接访问元类。
编写 @classproperty 装饰器
您实际上可以通过子类化property 在几行代码中创建一个classproperty 装饰器(它是用C 实现的,但您可以看到等效的Python here):
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))
然后将装饰器视为结合了属性的类方法:
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()
但我不确定这样做是否明智。旧的邮件列表 article 表明它不应该工作。
让属性在类上工作:
上面的缺点是“类属性”不能从类中访问,因为它只会覆盖类__dict__的数据描述符。
但是,我们可以使用元类__dict__ 中定义的属性来覆盖它。例如:
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
然后元类的类实例可以有一个属性,该属性使用前面部分已经演示的原理访问类的属性:
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'>
有权访问类属性。