代码之家  ›  专栏  ›  技术社区  ›  Paul Panzer

有没有一种方法可以将dict和collections.abc.MutableMapping进行子类化?

  •  2
  • Paul Panzer  · 技术社区  · 5 年前

    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__ 在本例中)已经由 迪克特

    有没有吃蛋糕的方法?一些魔法让 MutableMapping

    1 回复  |  直到 5 年前
        1
  •  2
  •   Raymond Hettinger    5 年前

    你能做什么:

    这可能不会很好地实现(即不是最干净的设计),但是您可以从 可变映射 迪克特

    那么 可变映射 将使用您实现的任何方法(因为它们是查找链中的第一个方法):

    >>> 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
    

    最干净的方法(易于理解和测试)是从 可变映射

    >>> 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