【问题标题】:Override __getitem__ to update覆盖 __getitem__ 以更新
【发布时间】:2018-06-13 12:18:54
【问题描述】:

我正在实现一个继承自 UserDict 的类。这个类完全符合预期,但我想扩展它的功能。我希望它通过在对字典进行操作时已被覆盖的所有方法。一个例子是:

from collections import UserDict


class DummyClass(UserDict):
    def __init__(self):
        self.mine = {}
        self.data = self.mine

    def __getitem__(self, key):
        print("Doing some stuff here")
        return self.data[key]

    def __setitem__(self, key, value):
        print(f"Uses my __setitem__ {key} {value}")
        self.data[key] = value

做的时候:

dd = DummyClass()
dd["one"] = {"two": 2}
print(f"First dict: {dd}") 

输出是:

Uses my __setitem__ one {'two': 2}
First dict: {'one': {'two': 2}}

然而,

dd["one"].update({"two": 4})
print(f"New dict: {dd.keys()}")

将使用修改后的 getitem 并使用基本方法更新。

Doing some stuff here
New dict: {'one': {'two': 4}}

我想要的是 dd["one"] 是一个可以修改的对象,可以调用修改后的 setitem 而无需执行 dd.update({"one": {"two": 4}})

我的问题是最好的方法是什么?在上面的例子中,我应该用getitem返回一个对象,修改它并返回它吗?我希望它尽可能通用。

与问题密切相关:

Subclassing Python dictionary to override __setitem__

但我想知道现在是否有新方法。

感谢任何帮助

【问题讨论】:

  • 不是 DummyClass 实例,它们是普通字典,所以不清楚为什么会令人惊讶。
  • 你的课真的很混乱。你为什么首先从UserDict 派生?你为什么要self.data = self.__dict__?这将允许通过属性访问语法访问字典中的项目,但它也会将字典与属性混为一谈,例如字典总是有一个关键的“数据”。总的来说,我不太清楚你想要实现什么,但我很确定你最好使用不是从 UserDictdict 派生的类,而是简单地使用字典来存储数据。
  • 我正在创建一个 API,其中的输出是一个字典,我想尽可能自然地操作它(UserDict 的原因)。我试图从头开始提供 MWE,我同意它是不一致的。这个想法是能够通过分配来填充字典,但也可以做类似上面的事情而不是dd.update({"one": {"two": 4}})
  • 当您执行dd["one"].update({"two": 4}) 时,您不是在dd 上调用update,而是在dd.__getitem__("one") 返回的值上调用(在这种情况下是普通字典{"two": 2} )。如果您想将值包装在另一个级别的自定义自定义字典中,则需要显式执行此操作(例如 dd["one"] = DummyClass({"two": 2})),或编写代码为您隐式执行包装(可能在 __getitem__ 中)。
  • 我看到我没有清楚地解释自己,对此感到抱歉。我对类的行为并不感到惊讶,如果可能的话,我希望 dd["one"] 返回一个对象,我可以使用一组自定义方法对其进行操作并将其返回到类字典而无需包装正如@Blckknght 所明确建议的那样。

标签: python dictionary subclass


【解决方案1】:

您可以将给定的内部字典作为值包装在类的另一个实例中。如果您希望这自动发生,我建议对您在__setitem__ 中传递的任何字典值执行此操作,因为这可以让您稍后更改包装器对象,同时在您的数据中保留对它的引用。

试试这样的:

def __setitem__(self, key, value):
    print(f"Uses my __setitem__ {key} {value}")
    if isisnstance(value, dict):
        wrapper = DummyClass()  # if __init__ accepts arguments use: value = DummyClass(value)
        wrapper.update(value)
        value = wrapper
    self.data[key] = value

示例输出:

>>> dd = DummyClass()

>>> dd["one"] = {"two": 2}
Uses my __setitem__ one {'two': 2}
Uses my __setitem__ two 2

>>> dd["one"].update({"two": 4})
Doing some stuff here
Uses my __setitem__ two 4

>>> print(dd)
{'one': {'two': 4}}

【讨论】:

  • 完美简洁的答案。谢谢!
猜你喜欢
  • 2020-12-28
  • 2020-07-02
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 2020-03-27
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
相关资源
最近更新 更多