链接 __getitem__ (d['a']['b']) 不适用于自定义字典包装器

Chaining __getitem__ (d['a']['b']) not working with custom dict wrapper

我有一本字典,其中每个键总是以特定字符串作为前缀。该字典可能如下所示:

d = {
    "aa123":{
        "aa456": "456",
        "aa789": "789"
    }
}

所以我正在编写一个包装器,我可以在其中查询字典而不使用前置字符串。例如:

print(d["123"]["456"]) # --> should print "456"

这是我的包装纸:

class CustDict(dict):
    def __init__(self, *args, **kwargs):
        self.ns = kwargs.pop("namespace")
        super().__init__(*args, **kwargs)

    def __getitem__(self, key):
        key = f"{self.ns}{key}"
        return super().__getitem__(key)

当我使用它时出现以下错误:

cust_d = CustDict(d, namespace="aa")
print(cust_d["123"]["456"])

我收到错误:

KeyError: '456'

现在,我知道这是因为 __getitem__ 正在返回 dict 而不是 CustDict 的实例。 但是,如果我将 return super().__getitem__(key) 替换为 return CustDict(k, namespace=self.ns),则会出现其他错误,例如 ValueError: dictionary update sequence element #0 has length 1; 2 is required

如有任何解决方案,我们将不胜感激。

首先,既然你想覆盖 __getitem__ 的实例方法,那么你不应该继承 dict。如果你继承自 dict 那么它甚至不会查看 __getitem__ 的实例方法。您可以了解更多相关信息 here. Instead use UserDict

对您的代码稍作修改,使其看起来如下所示:

from collections import UserDict

class CustDict(UserDict):
    def __init__(self, *args, **kwargs):
        self.ns = kwargs.pop("namespace")
        super().__init__(*args, **kwargs)

    def __getitem__(self, key):
        key = f"{self.ns}{key}"
        val = super().__getitem__(key)
        if isinstance(val, dict):
            return CustDict(val, namespace=self.ns)
        else:
            return val

cust_d = CustDict(d, namespace="aa")

cust_d["123"]
>> {'aa456': '456', 'aa789': '789'}

cust_d["123"]["456"]
>> '456'