【问题标题】:Confusion with properties与属性混淆
【发布时间】:2012-10-17 16:48:46
【问题描述】:

我是使用属性的新手,所以我整理了一个简单的测试,如下所示。在我的测试中,我创建了两个类“Test1”和“Test2”,每个类都包含一个值。我正在尝试使用属性来管理对伪隐藏“val”属性的访问。此当前测试不限制“val”属性的任何输入或输出,因为该程序仅作为概念证明。下面显示的两个测试类产生相同的结果,并且应该代表构造属性的不同方法。我所指的属性的示例使用在 python docs here 上。

根据documentation

如果 c 是 C 的实例,c.x 将调用 getter,c.x = value 将调用 setter,del c.x 将调用删除器。

其中 C 是他们的测试类。我认为通过以我所做的方式设置值会更改 _val 并将 val 作为属性。但是在我看来,我访问属性设置器的方法实际上是用整数 5 替换属性,除非我弄错了。我希望有人能澄清我的困惑。

class Test1:
    def __init__(self):
        self._val = 0

    def setVal(self,newVal):
        self._val = newVal
    val = property(lambda self: self._val, setVal, None, "Property for value")

    def __str__(self):
        return "Value: {}".format(self.val)

class Test2:
    def __init__(self):
        self._val = 0

    @property
    def val(self):
        return self._val

    @val.setter
    def setVal(self,newVal):
        self._val = newVal

    def __str__(self):
        return "Value: {}".format(self.val)

def verify(a):
    print("\nCheck with {}".format(a.__class__.__name__))
    print("Value check:",a.val)
    a.val = 5
    print("Value after a.val = 5 is:",a.val)
    print("The actual value is:",a._val)

def main():
    verify(Test1())
    verify(Test2())

if __name__ == '__main__':
    main()

【问题讨论】:

    标签: python properties


    【解决方案1】:

    来自documentation

    property([fget[, fset[, fdel[, doc]]]])

    返回新型类(派生自对象的类)的属性属性。

    只为新的样式对象或类调用描述符。您使用旧式课程。继承自基本类型object

    class Test1(object):
        # your code
    
    class Test2(object):
        def __init__(self):
            self._val = 0
        
        @property
        def val(self):
            return self._val
        
        @val.setter
        def val(self,newVal): # should be named as property
            self._val = newVal
        
        def __str__(self):
            return "Value: {}".format(self.val)
    

    这项工作很好:

    >>> verify(Test1())
    
    Check with Test1
    ('Value check:', 0)
    ('Value after a.val = 5 is:', 5)
    ('The actual value is:', 5)
    

    阅读更多关于difference between new-style classes and classic classes的信息。

    【讨论】:

    • 感谢您的那篇文章。不过我还有一个问题。正如您所说,我将每个班级更改为 object 班级的父班级。 Test1 完美运行,但 Test2 向我提供了错误:AttributeError: can't set attribute。有什么建议吗?
    • @jakebird451,对不起,在我这个星球的一侧是一个夜晚。 :) 来自文档:“确保为附加功能提供与原始属性相同的名称”。在这种情况下,您的 setter-function 应命名为 val