我已经看到了很多关于这个问题的答案,他们都说不可能将属性与类方法一起使用,但以下代码有效:
class A:
@classmethod
@property
def hello(cls):
print(1234)
>>> A.hello
1234
为什么以及如何工作?
在 CPython 3.9.1 上运行。
我已经看到了很多关于这个问题的答案,他们都说不可能将属性与类方法一起使用,但以下代码有效:
class A:
@classmethod
@property
def hello(cls):
print(1234)
>>> A.hello
1234
为什么以及如何工作?
在 CPython 3.9.1 上运行。
从 Python 3.9 开始,类方法触发描述符协议。来自Python 文档:
的代码路径
hasattr(obj, '__get__')
是在 Python 3.9 中添加的,并且可以classmethod()
支持链式装饰器。
令人惊讶的是,深入研究该主题会向您展示以类本身作为实例classmethod
触发描述符:__get__
class Descriptor:
def __get__(self, instance, owner):
print(instance, owner)
def __set__(self, value, owner):
print(value, owner)
class A:
regular = Descriptor()
clsmethod = classmethod(Descriptor())
>>> A.regular
None <class '__main__.A'>
>>> A.clsmethod
<class '__main__.A'> None
我猜他们是专门为支持描述符而设计的@property
,因为通过类访问它们会返回属性本身:
class B:
@property
def prop(self):
print(self)
>>> B.__dict__["prop"].__get__(None, 1234)
<property object at 0x000001BEEB635630>
>>> B.__dict__["prop"].__get__(1234, None)
1234
如果您希望同时支持普通描述符和普通描述符,这有点不直观,并且会使描述符协议变得笨拙classmethod
,因为您必须检查 is 是否owner
为None
.
但是请记住, __set__
不被调用(因为描述符协议在设置类属性时不会调用它),使您无法使用@property.setter
:
>>> A.regular = 1234
>>> A.regular
1234
>>> A.clsmethod = 1234
>>> A.clsmethod
1234