定义@property

时间:2015-08-12 09:58:46

标签: python python-2.7 properties abstract-class abc

我在使用具体类中的@property来定义getter时遇到问题。这是python代码:

from abc import ABCMeta, abstractproperty

class abstract(object):
    __metaclass__ = ABCMeta

    def __init__(self, value1):
        self.v1 = value1

    @abstractproperty
    def v1(self):
        pass

class concrete(abstract):
    def __init__(self, value1):
        super(concrete, self).__init__(value1)

    @property
    def v1(self):
        return self.v1

然后测试代码并得到此错误:

test_concrete = concrete("test1")
test_concrete.v1

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-190-eb896d7ec1c9> in <module>()
----> 1 test_concrete = concrete("test1")
      2 test_concrete.v1

<ipython-input-189-bf15021022d3> in __init__(self, value1)
     11 class concrete(abstract):
     12     def __init__(self, value1):
---> 13         super(concrete, self).__init__(value1)
     14 
     15     @property

<ipython-input-189-bf15021022d3> in __init__(self, value1)
      3 
      4     def __init__(self, value1):
----> 5         self.v1 = value1
      6 
      7     @abstractproperty

AttributeError: can't set attribute

基本上我打算将v1设置为只读属性。

我习惯使用相同的名称作为属性及其getter函数,但是如果类继承自抽象类,我似乎无法做到。

我找到了一种解决方法,将getter函数v1的不同名称用作get_v1

class abstract(object):
    __metaclass__ = ABCMeta

    def __init__(self, value1):
        self.v1 = value1

    @abstractproperty
    def get_v1(self):
        pass

class concrete(abstract):
    def __init__(self, value1):
        super(concrete, self).__init__(value1)

    @property
    def get_v1(self):
        return self.v1

这个问题有更好的解决方法吗?

1 个答案:

答案 0 :(得分:2)

您的问题与抽象类无关。这是命名空间问题;属性对象和实例属性占用相同的命名空间,不能同时具有实例属性和属性使用完全相同的名称。

您正在尝试使用self.v1 = ...访问属性,而v1并不是神奇的实例属性,因为您是从实例上的方法访问它, 总是将成为属性对象。

同样,你的属性getter会导致无限循环:

@property
def v1(self):
    return self.v1

因为self.v1 属性对象,而不是实例属性。

为实际存储使用其他名称:

def __init__(self, value1):
    self._v1 = value1

@property
def v1(self):
    return self._v1

请注意,您不能在Python中拥有真正的私有属性(就像在C#或Java中一样);名称上的前导下划线只是一个约定,确定的编码器总是可以直接访问您的实例状态。 property对象不会更改此内容。