__Python中具有只读属性的iadd
处理Python读写属性上的__Python中具有只读属性的iadd,python,Python,处理Python读写属性上的\uuu iadd\uu。但是,我正在努力找到只读属性的解决方案 在my MWE中,我们有一个只读属性Beta.value,返回一个Alpha实例。我想我应该能够在Beta.value上使用\uuuu iadd\uuuu,因为返回的值在适当的位置发生了变异,并且对Beta本身没有任何更改,就像它前面的“Beta.value.content+=”行一样。但是,以下代码与属性错误一起崩溃:无法设置属性 是否可以在只读属性上使用\uuuu iadd\uuuu class A
\uuu iadd\uu
。但是,我正在努力找到只读属性的解决方案
在my MWE中,我们有一个只读属性Beta.value
,返回一个Alpha
实例。我想我应该能够在Beta.value
上使用\uuuu iadd\uuuu
,因为返回的值在适当的位置发生了变异,并且对Beta
本身没有任何更改,就像它前面的“Beta.value.content+=
”行一样。但是,以下代码与属性错误一起崩溃:无法设置属性
是否可以在只读属性上使用\uuuu iadd\uuuu
class Alpha:
def __init__( self, content : int ) -> None:
self.content : int = content
def __iadd__( self, other : int ) -> "Alpha":
self.content += other
return self
class Beta:
def __init__( self ):
self.__value: Alpha = Alpha(1)
@property
def value( self ) -> Alpha:
return self.__value
beta = Beta()
beta.value.content += 2
beta.value += 2
人们在使用就地运算符时经常忘记的一点是,它们的使用总是涉及到赋值。你可以在Alpha.content
(或者任何int
或者str
中直观地看到这一点):整数是不可变的,但是操作是有效的。对于像Alpha
或list
这样的东西,很容易忘记这一步,其中就地操作符只返回self
。请记住,运算符可以返回任何内容,并且结果必须绑定到原始名称。这里发生的事情基本上是这样的:
x = beta.value
x = operator.iadd(x, 2) # Totally fine
beta.value = x # You can imagine how this would be a problem...
这样做的一个直接后果是,尽管出现了错误,您仍将看到beta.value
中的更改
欢迎您通过首先分配给临时变量来绕过重新分配,即显式运行上面显示的前两行。请记住,虽然在您的情况下,Alpha
是可变的,并且确实会在适当的位置修改自身,但这不是一般情况下的要求:
x = beta.value
x += 2
按预期工作。但是,
x = beta.value.content
x += 2
不会,因为int.\uuuu iadd\uuuu
不可避免地返回一个新引用。可以通过为只接受原始对象的属性添加特殊的setter来欺骗它
等级Beta
将变成:
class Beta:
def __init__( self ):
self.__value: Alpha = Alpha(1)
def _get_val( self ) -> Alpha:
return self.__value
def _set_val( self, val: Alpha):
if not (val is self.__value): # only accept the existing object
raise AttributeError("can't set attribute")
value = property(_get_val, _set_val)
有了这个技巧,您可以成功地使用:
>>> beta = Beta()
>>> beta.value.content
1
>>> beta.value = Alpha(2) # property IS read only
Traceback (most recent call last):
File "<pyshell#86>", line 1, in <module>
beta.value = Alpha(2)
File "<pyshell#78>", line 9, in _set_val
raise AttributeError("can't set attribute")
AttributeError: can't set attribute
>>> beta.value.content # and was not changed by an assignment attempt
1
>>> beta.value += 2 # but accepts augmented assignment
>>> beta.value.content
3
beta=beta()
>>>beta.value.content
1.
>>>beta.value=Alpha(2)#属性为只读
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
β值=α(2)
文件“”,第9行,输入值
引发AttributeError(“无法设置属性”)
AttributeError:无法设置属性
>>>beta.value.content#并且未被分配尝试更改
1.
>>>beta.value+=2#但接受增广赋值
>>>beta.value.content
3.
Related:甚至比这更糟糕:beta.value
会引发错误(这是预期的),但会增加beta.value.content
@Aran Fey很好地提醒了我们为什么x+=1
适用于不可变类型。