【问题标题】:Is there a way of subclassing from dict and collections.abc.MutableMapping together?有没有办法从 dict 和 collections.abc.MutableMapping 一起继承?
【发布时间】:2020-01-29 07:53:58
【问题描述】:

为了举例,假设我想继承 dict 并将所有键都大写:

class capdict(dict):
    def __init__(self,*args,**kwds):
        super().__init__(*args,**kwds)
        mod = [(k.capitalize(),v) for k,v in super().items()]
        super().clear()
        super().update(mod)
    def __getitem__(self,key):
        return super().__getitem__(key.capitalize())
    def __setitem__(self,key,value):
        super().__setitem__(key.capitalize(),value)
    def __delitem__(self,key):
        super().__detitem__(key.capitalize())

这在一定程度上有效,

>>> ex = capdict(map(reversed,enumerate("abc")))
>>> ex
{'A': 0, 'B': 1, 'C': 2}
>>> ex['a']
0

但是,当然,仅适用于我记得实现的方法,例如

>>> 'a' in ex
False

不是期望的行为。

现在,填充所有可以从“核心”方法派生的方法的懒惰方式 将混入collections.abc.MutableMapping。只是,它在这里不起作用。我想是因为有问题的方法(示例中为__contains__)已经由dict提供。

有没有办法让我的蛋糕吃掉?让MutableMapping 只看到我已覆盖的方法,以便它基于这些方法重新实现其他方法?

【问题讨论】:

  • 您可能不需要使用MutableMapping。见Case insensitive dictionary
  • @martineau 谢谢,我说过这只是一个例子。
  • 你可以使用os._Environ

标签: python python-3.x


【解决方案1】:

你能做什么:

这可能效果不佳(即不是最简洁的设计),但您可以先从 MutableMapping 继承,然后再从 dict 继承。

然后 MutableMapping 将使用您已实现的任何方法(因为它们是查找链中的第一个):

>>> class D(MutableMapping, dict):
        def __getitem__(self, key):
            print(f'Intercepted a lookup for {key!r}')
            return dict.__getitem__(self, key)


>>> d = D(x=10, y=20)
>>> d.get('x', 0)
Intercepted a lookup for 'x'
10
>>> d.get('z', 0)
Intercepted a lookup for 'z'
0

更好的方法:

最简洁的方法(易于理解和测试)是从 MutableMapping 继承,然后使用常规 dict 作为基础数据存储(使用组合而不是继承)实现所需的方法:

>>> class CapitalizingDict(MutableMapping):
        def __init__(self, *args, **kwds):
            self.store = {}
            self.update(*args, **kwds)
        def __getitem__(self, key):
            key = key.capitalize()
            return self.store[key]
        def __setitem__(self, key, value):
            key = key.capitalize()
            self.store[key] = value
        def __delitem__(self, key):
            del self.store[key]
        def __len__(self):
            return len(self.store)
        def __iter__(self):
            return iter(self.store)
        def __repr__(self):
            return repr(self.store)


>>> d = CapitalizingDict(x=10, y=20)
>>> d
{'X': 10, 'Y': 20}
>>> d['x']
10
>>> d.get('x', 0)
10
>>> d.get('z', 0)
0
>>> d['w'] = 30
>>> d['W']
30

【讨论】:

  • 谢谢!我可以发誓我尝试了这两个命令...出于兴趣,当我使用“可以做”方法将所有supers 换出显式dicts 然后它似乎工作,除了len 返回@ 987654326@。这是从哪里来的?
  • 来自 __len_()__ 的 super() 调用转到 mro 中的下一个:(D, MutableMapping, dict)。那就是总是返回 0 的 MutableMappiing.__len__() 方法。它不打算直接调用——它总是应该被覆盖。这就是为什么您必须直接致电dict.__len__(self)。这就是我说“这可能不会奏效”的原因之一;-)
猜你喜欢
  • 2011-01-14
  • 1970-01-01
  • 2015-05-01
  • 2016-09-18
  • 1970-01-01
  • 2023-04-01
  • 2018-07-07
  • 2011-02-16
相关资源
最近更新 更多