多态映射类型

Mor*_*enn 2 python mapping polymorphism dictionary

Python中是否有类似多面体的类似dict的类型?这里是我的意思是多态:考虑一个基本的类层次结构与Animal基类和一些派生类Cat,Snake等等,让我们有我们的神秘映射类型mystery_dict

mapping = mystery_dict({
    Animal : 'foo',
    Cat    : 'bar',
    Snake  : 'baz',
    Python : 'eggs',
    Boa    : 'spam'
})
Run Code Online (Sandbox Code Playgroud)

现在,我希望以下几行成立:

mapping[Animal]   == 'foo'
mapping[Cat]      == 'bar'
mapping[Dog]      == 'foo' # No Dog in mapping, take the base class Animal
mapping[Snake]    == 'baz'
mapping[Boa]      == 'spam'
mapping[Anaconda] == 'baz' # No Anaconda in mapping, take the base class Snake
Run Code Online (Sandbox Code Playgroud)

我知道自从Python 3.4以来我可以使用一堆isinstance或"重载集",functools.singledispatch但在某些情况下,多态字典类型可以方便地减少样板.这种类型是存在于野外还是我必须创建一个?当然,如果你有更好的选择,我会很高兴听到它.

注意:以防问题被提出,我有相当简单的需求,所以它不必处理多重继承.

Mar*_*ers 5

这对于自己来说是微不足道的:

from collections.abc import MutableMapping


class PolymorphicDict(MutableMapping):
    def __init__(self, *args, **kwargs):
        self._mapping = dict(*args, **kwargs)

    def __getitem__(self, key):
        for cls in key.__mro__:
            if cls in self._mapping:
                return self._mapping[cls]
        raise KeyError(key)

    def __delitem__(self, key):
        del self._mapping[key]

    def __setitem__(self, key, value):
        self._mapping[key] = value

    def __iter__(self):
        return iter(self._mapping)

    def __len__(self):
        return len(self._mapping)
Run Code Online (Sandbox Code Playgroud)

这使用该class.__mro__属性以方法查找顺序(Method Resolution Order)列出当前对象的类层次结构.此序列包括当前类,并列出所有类object.

演示:

>>> class Animal: pass
... 
>>> class Cat(Animal): pass
... 
>>> class Dog(Animal): pass
... 
>>> class Snake(Animal): pass
... 
>>> class Python(Snake): pass
... 
>>> class Boa(Snake): pass
... 
>>> class Anaconda(Snake): pass
... 
>>> Anaconda.__mro__
(<class '__main__.Anaconda'>, <class '__main__.Snake'>, <class '__main__.Animal'>, <class 'object'>)
>>> mapping = PolymorphicDict({
...     Animal : 'foo',
...     Cat    : 'bar',
...     Snake  : 'baz',
...     Python : 'eggs',
...     Boa    : 'spam'
... })
>>> mapping[Animal]
'foo'
>>> mapping[Cat]
'bar'
>>> mapping[Dog]
'foo'
>>> mapping[Snake]
'baz'
>>> mapping[Boa]
'spam'
>>> mapping[Anaconda]
'baz'
Run Code Online (Sandbox Code Playgroud)

你可能想看看zope.component; 这使您可以使用添加的接口完成此操作.它已经将查找映射优化到非常高的程度,以将原理扩展到更大的对象映射注册表.