这是 Python 的后续问题:如何将 int 与 @property 的值相加/相乘
在最初的问题中,我想对属性(与类属性相关)的值进行算术运算;我发现我必须将属性定义为类方法。
现在假设我也希望能够更改该属性,例如:
class A:
__att = 3
@classmethod
@property
def att(cls):
return cls.__att
"""
@classmethod
@att.setter
def att(cls, val):
cls.__att = val
"""
@classmethod
def changeAtt(cls, val):
cls.__att = val
def test_method(self):
return 3*A.att
a = A()
a.att = 5 #adding "att" to instance
print(a.test_method())
a.changeAtt(5)
print(a.test_method())
输出是
9
15
Tha 方法
changeAtt
做我想做的事,所以这是可以完成的,但是如果我试图取消注释属性设置器,我会得到一个错误:
@att.setter AttributeError: 'classmethod' object has no attribute 'setter'
我也试过颠倒装饰器的顺序,没有结果。 再一次:我错过了什么?
简而言之,
att
不是财产;这是一个类方法。它根本没有 setter
方法用作装饰器来添加 setter。颠倒装饰器的顺序是行不通的,因为 classmethod
对象本身是不可调用的;只有 classmethod
的 __get__
方法 returns 是可调用的。
可以通过不使用
property
作为装饰器来解决这个问题,而是使用类似 的东西明确地传递两个参数
class A:
__att = 3
@classmethod
def att_getter(cls):
return cls.__att
@classmethod
def att_setter(cls, val):
cls.__att = val
att = property(att_getter, att_setter)
del att_getter, att_setter
...
但是还有一个问题。颠倒装饰器的顺序,或者根本不使用
property
作为装饰器,是行不通的,因为 classmethod
对象本身是不可调用的;只有 classmethod
的 __get__
方法 returns 是可调用的。
classmethod
是非数据描述符;它只有一个 __get__
方法,所以虽然您可以 retrieve 类方法用 A.att
之类的东西包装,但没有 __set__
方法(像 property
这样的数据描述符有)来定义什么 A.att = ...
意味着.
此外,即使能够模仿人们想象的“类属性”的行为方式也是由于
classmethod.__get__
中已弃用的 Python-3.11 代码路径,这导致 A.att
“递归”调用 __get__
任何 A.__dict__['att'].__get__
都会返回的方法。您现在可以通过组合 classmethod
和 property
来定义相当于只读类属性的内容,但据我所知,这在未来的 Python 版本中将不起作用。
正如 chepner 提到的,在 python 中使用 @property 与 @classmethod 和 @xxx.setter 有一些限制。
但是有一个使用元类的解决方法:
class MyMetaClass(type):
__att = 8
@property
def att(cls):
return cls.__att
@att.setter
def att(cls, value):
cls.__att = value
class A(metaclass=MyMetaClass):
pass
print(A.att)
这在 python 3.10 和 3.11 中运行良好