为什么我不能通过继承OrderedDict和defaultdict来创建默认的,有序的dict?

drs*_*drs 11 python multiple-inheritance ordereddictionary python-3.x defaultdict

我首次尝试将collections模块中两个字典的功能组合在一起,创建一个继承它们的类:

from collections import OrderedDict, defaultdict

class DefaultOrderedDict(defaultdict, OrderedDict):
    def __init__(self, default_factory=None, *a, **kw):
        super().__init__(default_factory, *a, **kw)
Run Code Online (Sandbox Code Playgroud)

但是,我无法为此词典分配项目:

d = DefaultOrderedDict(lambda: 0)
d['a'] = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.3/collections/__init__.py", line 64, in __setitem__
    self.__map[key] = link = Link()
AttributeError: 'DefaultOrderedDict' object has no attribute '_OrderedDict__map'
Run Code Online (Sandbox Code Playgroud)

实际上,关于如何创建类似对象的这个问题有通过扩展OrderedDict类并手动重新实现所提供的其他方法来实现它的答案defaultdict.使用多重继承会更清晰.为什么不起作用?

Ash*_*ary 5

原因是代替在MRO中调用下一个类的init方法defaultdict__init__调用init,PyDict_Type因此__mapOrderedDict__init__中设置的某些属性从未被初始化,因此错误.

>>> DefaultOrderedDict.mro()
[<class '__main__.DefaultOrderedDict'>,
 <class 'collections.defaultdict'>,
 <class 'collections.OrderedDict'>,
 <class 'dict'>, <class 'object'>]
Run Code Online (Sandbox Code Playgroud)

而且defaultdict没有自己的__setitem__方法:

>>> defaultdict.__setitem__
<slot wrapper '__setitem__' of 'dict' objects>
>>> dict.__setitem__
<slot wrapper '__setitem__' of 'dict' objects>
>>> OrderedDict.__setitem__
<unbound method OrderedDict.__setitem__>
Run Code Online (Sandbox Code Playgroud)

所以,当你调用d['a']= 1时,在搜索__setitem__Python时到达OrdereredDict __setitem__并且他们对未初始化__map属性的访问引发了错误:


修复将是__init__两个defaultdictOrderedDict明确调用:

class DefaultOrderedDict(defaultdict, OrderedDict):
    def __init__(self, default_factory=None, *a, **kw):
        for cls in DefaultOrderedDict.mro()[1:-2]:
            cls.__init__(self, *a, **kw)
Run Code Online (Sandbox Code Playgroud)