问题描述
我想在返回类之前在类的getter中更改字典。我可以想象这个问题已经回答了,但是我找不到。有类似的问题谈论字典中键的重新索引/重新映射,但它们无法回答我的问题。
因此,我的假设是,getter返回self._d
,然后查找键a
并更新值。让我感到困惑的是,a.d['a'] = 2
的分配并没有改变字典。
class A:
def __init__(self):
self._d = None
@property
def d(self):
self._d['a'] = 4 # this line changes the behavior
return self._d
@d.setter
def d(self,value):
self._d = value
a = A()
a.d = {'a': 1}
a.d['a'] = 2
print("a.d: ",a.d['a']) # prints 4
解决方法
实际上,最后的打印将其重置为4。
我建议您看看像http://pythontutor.com这样的可视化工具中的执行状态。您将了解发生了什么
如果将打印语句添加到每个函数中,您将看到这里发生的事情:
class A:
def __init__(self):
print("init is called")
self._d = None
@property
def d(self):
print("property is called")
self._d['a'] = 4 # this line changes the behavior
return self._d
@d.setter
def d(self,value):
print("setter is called")
self._d = value
然后我们遍历您的代码:
In [23]: a = A()
init is called
In [24]: a.d
property is called
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-24-ebaff4a357c2> in <module>
----> 1 a.d
<ipython-input-22-687b3aea38f8> in d(self)
7 def d(self):
8 print("property is called")
----> 9 self._d['a'] = 4 # this line changes the behavior
10 return self._d
11
TypeError: 'NoneType' object does not support item assignment
In [26]: a.d = {"a": 1}
setter is called
In [27]: a.d
property is called
Out[27]: {'a': 4}
In [28]: a.d["a"] = 2
property is called
首先要注意的是,在赋值之前调用a.d
会导致错误,因为我们尚未初始化变量。 (这不是您要的,只是以为我会指出。)
第二,请注意,第一次分配a.d时会调用setter,但更新密钥时会不是 -实际上,更新密钥时会调用property方法。
如果我们添加更多打印语句以打印出self._d
和value
的值,我们可以看到self._d["a"]
在覆盖之前等于2。首先,我们将属性设置为等于dict,然后访问该属性。
In [4]: a.d = {"a": 2}
self._d: None
value: {'a': 2}
setter is called
In [5]: a.d
self._d: {'a': 2}
property is called
Out[5]: {'a': 4}
使用这样的打印语句来了解这些功能是如何工作的,可以帮助您了解这些功能。希望这可以帮助您了解内部工作原理,以便您可以调整代码以获得所需的结果。