在getter方法中为dict赋值

问题描述

我想在返回类之前在类的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._dvalue的值,我们可以看到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}

使用这样的打印语句来了解这些功能是如何工作的,可以帮助您了解这些功能。希望这可以帮助您了解内部工作原理,以便您可以调整代码以获得所需的结果。