如何防止Python中类字段(列表)的更改?

如何防止Python中类字段(列表)的更改?,python,Python,例如,我有一个带有字段\uuux的类,它是一个列表: class C(): def __init__(self, xx): self.__x = xx @property def x(self): return self.__x @x.setter def x(self, xx): raise Exception("Attempt to change an immutable field") 我可以防止以下

例如,我有一个带有字段
\uuux
的类,它是一个列表:

class C():
    def __init__(self, xx):
        self.__x = xx
    @property
    def x(self):
        return self.__x
    @x.setter
    def x(self, xx):
        raise Exception("Attempt to change an immutable field")
我可以防止以下更改:

c = C([1,2,3])
c.x = [3,2,1]
但我怎样才能防止这样的变化呢

c.x.append(4)

归根结底,您无法保护对象免受检查和操纵。 此外,当您想“保护”数据时,始终要问自己“到底是谁提供的?”

有时,围绕不阅读文档的用户编写代码是不值得的

以上所说的,可以在吸气剂中考虑<代码>返回元组(自已.x x)。 另一方面,如果

\uux
包含其他可变对象,则不会阻止用户操作这些内部对象。(
返回列表(self.\ux)
也将返回数据的浅拷贝,但不太隐含“嘿,我应该是不可变的!”信号。)

<> P> >你应该明确考虑的是,将<代码> So.yxx=XX < /C> > <代码> >
var = []
c = C(var)

无法通过变异
var

来“轻松”(或者错误地,可能存在可变的内部对象)更改
c
的状态最简单的方法是在
\uuuuu init\uuuu>上接受一个iterable,并在内部将其转换为元组:

class C(object):
    def __init__(self, iterable):
        self._tuple = tuple(iterable)

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

    @x.setter
    def x(self, value):
      raise RuntimeError('can\'t reset the x attribute.')

c = C([1, 2, 3])
# c.x = 'a' Will raise 'RuntimeError: can't reset the x attribute.'
print(c.x)
这样的设计使得从类实例化的任何对象都是不可变的,因此变异操作应该返回新对象,而不是更改当前对象的状态

例如,假设您想要实现一个函数,该函数在
self.x
中的每个项递增一。使用这种方法,您需要编写类似于:

def increment_by_one(c):
  return C(t+1 for t in c.x)

由于创建和销毁对象会带来成本,因此这种方法(防止
x
属性突变)和@timgeb建议的方法之间的权衡应该在您的用例中进行评估。

您真的不能。在Python中,试图使事物不可变是相当困难的,除非您想编写C扩展。在这里,
list
对象总是可变的,您可以定义一个“不可变”包装器。注意,您只需不定义setter,它就会抛出error@juanpa.arrivillaga那么在我的类中使用元组可以吗?每次我想要列表时,我都会使用list(self.\ux)。或者这是一种不好的做法?将列表转换为元组如何?当然,您也可以返回列表的副本,然后
。append
根本不会matter@ttt那么,使用一个列表并返回它的一个副本,或者如果愿意的话返回一个元组,但是一个副本可以
self.\u x.copy()
(还有
copy.deepcopy
,但如果使用每个属性访问调用,则不值得付出努力,而且代价高昂。)@juanpa.arrivillaga不适用于具有可变内部对象的列表,例如列表列表。当然,但是
C
可能依赖于
\u tuple
在内部是可变的。@timgeb不是我从操作中推断出来的请求。如果一个突变操作返回不同的实例,那么这样的类(不可变)可能是有意义的。