如何在 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 的值无论如何。
在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 的值无论如何。