【问题标题】:Assign value to dict in getter method在getter方法中为dict赋值
【发布时间】:2020-08-24 19:38:50
【问题描述】:

我想在返回类的 getter 中更改字典。我可以想象这个问题已经回答了,但我找不到。有类似的问题讨论了 dict 中键的重新索引/重新映射,但它们没有回答我的问题。 因此,我的假设是 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

【问题讨论】:

  • 你的 print 语句中的 getter 将它重置回 4
  • 如果您在执行a.d['a']=2 之后和print 语句之前查看a._d['a'],您将看到它确实成功地更改了字典。跨度>
  • @alani 在 print 声明之前你是如何看待a.d 的?使用我的调试器(pycharm),我从来没有看到值变为 2。
  • 我没有。我查看了基础属性a._d。每次您尝试查看 a.d 时,您都会调用您的 getter 方法,它会覆盖它,所以我并不惊讶您没有看到任何变化。
  • 确实,您接受的答案正是如此(检查a._d) - 请参阅“如果我们添加更多打印语句”开头的段落

标签: python properties getter


【解决方案1】:

如果您向每个函数添加打印语句,您可以看到这里发生了什么:

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,但更新 key 时不会 - 实际上是在更新 key 时调用 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}

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

【讨论】:

  • 非常感谢您的详细解答!
  • 你们运行的是什么 Python 版本?我看不到属性打印:(
  • Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32 输入“帮助”,“ copyright”、“credits”或“license”了解更多信息。
  • 奇怪的是我在调试器(pycharm)中没有看到这种行为。我同意 getter 中的分配是在 a.d["a"] = 2 之后完成的,因此 2 被覆盖,但我没有看到在 self._d['a'] = 4 之前设置为 2 的键 a
  • @Thomas -- 我在答案中添加了另一个简短示例,显示了如果您在函数中打印出 self._dvalue 的值会发生什么。看起来调用 a.d["a"] = 2 实际上并没有对 2 的值做任何事情,因为只有 @property 方法被调用。仅当您尝试设置 a.d 自身时才会调用 setter。
【解决方案2】:

实际上,您最后的打印会将其重置为 4。
我建议你看看像http://pythontutor.com 这样的可视化工具中的执行状态。你会明白发生了什么

【讨论】:

  • @alani 当我删除 print 语句并使用调试器时,a 仍然是 4。
  • 刚试过pythontutor,最后没有print语句,self._d['a'] = 2。
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 2018-05-27
  • 2012-03-18
  • 1970-01-01
  • 2014-07-14
  • 1970-01-01
  • 1970-01-01
  • 2011-02-18
相关资源
最近更新 更多