如何使只读 属性 可变?
How can I make a read-only property mutable?
我有两个 类,一个带有 "in-place operator" 覆盖(例如 +=
),另一个通过 @property
公开第一个实例。 (注意:这是 大大 从我的实际代码简化到重现问题的最小值。)
class MyValue(object):
def __init__(self, value):
self.value = value
def __iadd__(self, other):
self.value += other
return self
def __repr__(self):
return str(self.value)
class MyOwner(object):
def __init__(self):
self._what = MyValue(40)
@property
def what(self):
return self._what
现在,当我尝试在暴露的 属性 上使用该运算符时:
>>> owner = MyOwner()
>>> owner.what += 2
AttributeError: can't set attribute
根据我的发现,这是意料之中的,因为它试图在 owner
上设置 属性。 有什么方法可以防止将 属性 设置为新对象,同时仍然允许我(就地)修改 它背后的对象,或者这只是语言的怪癖?
(另请参阅 this question,但我正在尝试另一种方式,最好是 而不是 恢复到旧式 类 因为最终我希望它与 Python 一起工作 3.)
与此同时,我用一种方法解决了这个问题。
class MyValue(object):
# ...
def add(self, other):
self.value += other
>>> owner = MyOwner()
>>> owner.what.add(2)
>>> print(owner.what)
42
这是语言的怪癖; object += value
操作转换为:
object = object.__iadd__(value)
这是必要的,因为并非所有对象都是可变的。你的是,并且正确 returns self
导致上述操作的分配部分虚拟无操作。
在你的例子中,有问题的 object
也是一个属性,因此执行以下内容:
owner.what = owner.what.__iadd__(2)
除了避免在左侧引用 object.what
(如 tmp = owner.what; tmp += 2
),还有一种方法可以干净利落地处理。
您可以很容易地检测到 属性 的分配涉及 相同的对象 并对其进行门控:
class MyOwner(object):
def __init__(self):
self._what = MyValue(40)
@property
def what(self):
return self._what
@what.setter
def what(self, newwhat):
if newwhat is not self._what:
raise AttributeError("can't set attribute")
# ignore the remainder; the object is still the same
# object *anyway*, so no actual assignment is needed
演示:
>>> owner = MyOwner()
>>> owner.what
40
>>> owner.what = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 24, in what
AttributeError: can't set attribute
>>> owner.what += 2
>>> owner.what
42
我有两个 类,一个带有 "in-place operator" 覆盖(例如 +=
),另一个通过 @property
公开第一个实例。 (注意:这是 大大 从我的实际代码简化到重现问题的最小值。)
class MyValue(object):
def __init__(self, value):
self.value = value
def __iadd__(self, other):
self.value += other
return self
def __repr__(self):
return str(self.value)
class MyOwner(object):
def __init__(self):
self._what = MyValue(40)
@property
def what(self):
return self._what
现在,当我尝试在暴露的 属性 上使用该运算符时:
>>> owner = MyOwner()
>>> owner.what += 2
AttributeError: can't set attribute
根据我的发现,这是意料之中的,因为它试图在 owner
上设置 属性。 有什么方法可以防止将 属性 设置为新对象,同时仍然允许我(就地)修改 它背后的对象,或者这只是语言的怪癖?
(另请参阅 this question,但我正在尝试另一种方式,最好是 而不是 恢复到旧式 类 因为最终我希望它与 Python 一起工作 3.)
与此同时,我用一种方法解决了这个问题。
class MyValue(object):
# ...
def add(self, other):
self.value += other
>>> owner = MyOwner()
>>> owner.what.add(2)
>>> print(owner.what)
42
这是语言的怪癖; object += value
操作转换为:
object = object.__iadd__(value)
这是必要的,因为并非所有对象都是可变的。你的是,并且正确 returns self
导致上述操作的分配部分虚拟无操作。
在你的例子中,有问题的 object
也是一个属性,因此执行以下内容:
owner.what = owner.what.__iadd__(2)
除了避免在左侧引用 object.what
(如 tmp = owner.what; tmp += 2
),还有一种方法可以干净利落地处理。
您可以很容易地检测到 属性 的分配涉及 相同的对象 并对其进行门控:
class MyOwner(object):
def __init__(self):
self._what = MyValue(40)
@property
def what(self):
return self._what
@what.setter
def what(self, newwhat):
if newwhat is not self._what:
raise AttributeError("can't set attribute")
# ignore the remainder; the object is still the same
# object *anyway*, so no actual assignment is needed
演示:
>>> owner = MyOwner()
>>> owner.what
40
>>> owner.what = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 24, in what
AttributeError: can't set attribute
>>> owner.what += 2
>>> owner.what
42