在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()
是否考虑成为一种好的做法?我应该只依靠文档来展示哪些属性是可写的,哪些不是?还有其他建议吗?
答案 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 拒绝对其进行修改。
效果如何,取决于数据结构的细节。例如,如果您的属性是列表,则可以拦截对列表本身的修改,但如果它具有可变元素,您仍然可以修改其属性。