通过属性与通过文档的只读属性

时间:2015-06-03 11:52:43

标签: python properties attributes private readonly

在Python中,我正在编写一个类,其中某些属性在对象生存期内必须保持不变。

一种方法是使用属性:

class Foo:
    def __init__(self, x, y):
        '''Create a Foo object

        x -- list of int (READ-ONLY)
        y -- float
        '''
        # Save x and y and ensure they are int
        self._x = [int(xx) for xx in x]
        self.y = float(y)

    @property
    def x(self):
        # Return a copy of self._x to prevent accidental modification
        return self._x.copy()

是否考虑成为一种好的做法?我应该只依靠文档来展示哪些属性是可写的,哪些不是?还有其他建议吗?

4 个答案:

答案 0 :(得分:1)

首先请注意,几乎没有任何技术方法可以阻止某人访问您的对象的实现并修改它,如果他真的想要的话。

现在wrt /你的问题/例子:

  • 使用实现属性(tuple())和readonly属性使意图非常清晰

  • 如果您的列表确实应该是不可变的,请改用tuple。它在语义上是有争议的({{1}}用于基于位置的记录 - 想想关系数据库记录等 - 不是不可变列表),但要确保它是不可变的并且避免必须复制。

  • 你仍然想清楚地记录这个属性应该为实例的生命周期“保持不变”。

答案 1 :(得分:1)

您可以稍微修改您的代码,以获得至少一个投诉

class Foo:
    def __init__(self, x, y):
        '''Create a Foo object

        x -- list of int (READ-ONLY)
        y -- float
        '''
        # Save x and y and ensure they are int
        self._x = [int(xx) for xx in x]
        self.y = float(y)

    @property
    def x(self): return self._x

    @x.setter
    def x(self,value):
        raise AttributeError('Don\'t touch my private parts, please')

然后如果你试图改变一切:

>>>> a = Foo([1,2,3,4,5],0.2)

>>>> a.x
     [1, 2, 3, 4, 5]

>>>> a.x = 3
Traceback (most recent call last):

  File "<ipython-input-87-0a024de0ab56>", line 1, in <module>
    a.x = 3

  File "D:/pydump/gcd_lcm_tests.py", line 230, in x
    raise AttributeError('Don\'t touch my private parts, please')

AttributeError: Don't touch my private parts, please

我可以静静地pass而不是提出异常,但在我看来最好抱怨。

答案 2 :(得分:0)

我相信你所追求的是:

示例#1:

from collections import namedtuple

foo = namedtuple("Immutable", ["a", "b"])

示例#2:

class Foo(object):
    __slots__ = ()

在这两种情况下,设置属性或以任何方式改变对象都是错误的。

<强>演示(S):

>>> from collections import namedtuple
>>> class Foo(object):
...     __slots__ = ()
... 
>>> Bar = namedtuple("Bar", ["a", "b"])
>>> foo = Foo()
>>> bar = Bar(1, 2)
>>> foo.a = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'a'
>>> foo.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'a'
>>> bar.a
1
>>> bar.a = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

请注意,对于namedtuple对象,一旦创建它们就无法更改其中的任何属性。这非常方便。

答案 3 :(得分:0)

如果您希望某个属性不可修改,会在解除引用时返回一个副本:您只会进一步混淆并导致奇怪的错误。如果要强制执行不可修改性,请将其设置为属性并使 setter 拒绝对其进行修改。

效果如何,取决于数据结构的细节。例如,如果您的属性是列表,则可以拦截对列表本身的修改,但如果它具有可变元素,您仍然可以修改属性。