如何在 Python 中管理对可变属性的访问

How to manage access to a mutable attribute in Python

在Python中,我们可以使用@属性装饰器来管理对属性的访问。例如,如果我们定义 class:

class C:
    def __init__(self,value):
        self._x = value

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

我们可以获取 x 的值,但不能更改它:

c = C(1)
#c.x = 4  # <= this would raise an AttributeError: can't set attribute

但是,如果属性是可变类型(例如列表),我们可以为属性的位置设置不同的值:

c = C([0,0])
c.x[0] = 1 # <= this works

有什么办法可以预防吗?如果 x 是一个列表,我希望能够仅使用 class C.

的方法更改 x 的位置值

一种方法是 return 属性的副本,而不是列表本身。

>>> class C:
...     def __init__(self, value):
...         self._x = value
...     @property
...     def x(self):
...         return self._x[:]
... 
>>> c = C([1, 2, 3])


>>> c.x
[1, 2, 3]
>>> c.x.append(5)
>>> c.x
[1, 2, 3]
>>> c.x[0] = 6
>>> c.x
[1, 2, 3]

或者,属性 可以 return 一个 iterator over attribute, or a view(例如 dict.items() 而不是字典)。如果属性很大,返回迭代器或视图可能有助于限制内存使用,并且更符合现代 Python 内置函数和类型的行为。

如果可变属性本身包含可变属性 - 例如列表或字典的列表 - 那么可能有必要 return 也复制这些对象。如果对象图很深,这在时间和资源方面可能会很昂贵。有关自定义对象复制方式的方法,请参阅 copy 模块的文档。

technique 通常用于防止 别名问题 - 其他对象持有对您对象内部状态的引用。

这确实意味着副本可能会与真实属性不同步,但如果您的代码设计得当,那么其他 classes 不应该保留您的 class 的值无论如何。