Python:如何添加@classmethod @property.setter

问题描述 投票:0回答:2

这是 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'

我也试过颠倒装饰器的顺序,没有结果。 再一次:我错过了什么?

python decorator python-decorators
2个回答
1
投票

简而言之,

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 版本中将不起作用。


0
投票

正如 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 中运行良好

© www.soinside.com 2019 - 2024. All rights reserved.