【问题标题】:Updating a dict attrib from an extended class updates the base class. Why?从扩展类更新字典属性会更新基类。为什么?
【发布时间】:2012-03-06 08:57:09
【问题描述】:
>>> class Test(object):
...   test = {}
... 
>>> class Test2(Test):
...   pass
... 
>>> Test2.test.update({1:2})
>>> Test.test
{1: 2}
>>> 

我期待{}。旧式类也会发生。

【问题讨论】:

  • 想解释一下为什么你会解释不同的东西? “test”类属性的 Test2 实例来自哪里?纯魔法?

标签: python class dictionary extends


【解决方案1】:

您需要使用 2 个下划线来激活类/属性修改

>>> class Test(object):
...     __test = {}
...
>>> class Test2(Test):
...     pass
...
>>> Test2.__test.update({1:2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Test2' has no attribute '__test'

由于属性修改,属性可以在Test2._Test__test找到

如果您希望所有子类自动获取它们自己的__test 属性,您可以为Test 使用元类

【讨论】:

  • 糟糕。对不起。我并不是真的想隐藏这个属性。
  • 设置属性本身不会更新基类。字典的更新方法有点奇怪。
【解决方案2】:

update 的工作方式并不奇怪。关键是testclass attribute,并且类属性在类之间共享,(直到有人将test 重新绑定到其他东西)。

看看这个 IDE 会话:

>>> class Test(object):
...     test = {}
... 
>>> class Test2(Test):
...     pass
... 
>>> id(Test.test)
32424144
>>> id(Test2.test)
32424144
>>> Test.test.update({1:2})
>>> Test2.test
{1: 2}
>>> Test2.test = {}
>>> id(Test2.test)
32424480
>>> Test.test
{1: 2}
>>> Test2.test
{}
>>> del Test2.test
>>> Test2.test
{1: 2}

有关类属性如何工作的更多信息,请查看类下的Data Model Reference

【讨论】:

    【解决方案3】:
    Test2.test.update({1:2})
    

    这会更新您的基类 Test 属性,该属性由 Test2 继承。

    如果您希望他们每个人都有自己的字典,请执行以下操作:

    >>> class Test(object):
    ...     test = {}
    ... 
    >>> class Test2(Test):
    ...     test = {}
    ... 
    >>> Test2.test.update({1:2})
    >>> Test.test
    {}
    >>> 
    

    Python 有一个我非常喜欢的特性:数据继承,您刚刚看到了它的实际应用。

    【讨论】:

      【解决方案4】:

      这是一个参考问题。举个例子:

      >>> class Test(object):
      ...   val = 1
      ... 
      >>> class Test2(Test):
      ...   pass
      ... 
      >>> Test2.val = 2
      >>> Test.val
      1
      

      这里对于子类val被重新赋值为2。

      对于列表和字典都引用同一个对象,并且任何更新/追加都将在超类中可见。但是,如果您重新签名:

      >>> class Test(object):
      ...   test = {}
      ... 
      >>> class Test2(Test):
      ...   pass
      ... 
      >>> Test2.test = {1:2}
      >>> Test.test
      {}
      

      【讨论】:

        【解决方案5】:

        因为它们是同一个对象。更准确地说,Test2.test 是一种访问与 Test.test 相同的方法,因为当它在本地找不到时,它会在超类中查找。

        我不明白你为什么会有不同的期望。 (在我能想到的任何其他语言中,它也不像您期望的那样工作。)

        【讨论】:

          猜你喜欢
          • 2020-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多