为什么不能通过继承OrderedDict和defaultdict创建默认的有序dict? [英] Why can't I create a default, ordered dict by inheriting OrderedDict and defaultdict?
问题描述
我首先尝试在collections
模块中结合两个词典的功能,是创建一个继承它们的类:
My first attempt to combine the features of two dictionaries in the collections
module was to create a class that inherits them:
from collections import OrderedDict, defaultdict
class DefaultOrderedDict(defaultdict, OrderedDict):
def __init__(self, default_factory=None, *a, **kw):
super().__init__(default_factory, *a, **kw)
但是,我无法为该词典分配项目:
However, I cannot assign an item to this dictionary:
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'
实际上,有关如何创建相似对象的问题具有通过扩展OrderedDict
类来实现的答案并手动重新实现defaultdict
提供的其他方法.使用多重继承会更干净.为什么不起作用?
Indeed, this question about how to create a similar object has answers that achieve it by extending the OrderedDict
class and manually re-implementing the additional methods provided defaultdict
. Using multiple inheritance would be cleaner. Why doesn't it work?
推荐答案
原因是defaultdict 的rel ="nofollow"> init
方法,而不是在MRO中调用下一个类的__init__
,而是调用PyDict_Type
的init,因此在其中设置了某些属性,例如__map
OrderedDict的__init__
从未初始化,因此错误.
The reason is that the init
method of defaultdict
instead of calling __init__
of the next class in MRO calls init of PyDict_Type
hence some of the attributes like __map
that are set in OrderedDict's __init__
are never initialized, hence the error.
>>> DefaultOrderedDict.mro()
[<class '__main__.DefaultOrderedDict'>,
<class 'collections.defaultdict'>,
<class 'collections.OrderedDict'>,
<class 'dict'>, <class 'object'>]
和defaultdict
没有自己的__setitem__
方法:
>>> defaultdict.__setitem__
<slot wrapper '__setitem__' of 'dict' objects>
>>> dict.__setitem__
<slot wrapper '__setitem__' of 'dict' objects>
>>> OrderedDict.__setitem__
<unbound method OrderedDict.__setitem__>
因此,当您调用d['a']
= 1时,搜索__setitem__
时,Python到达了OrdereredDict的__setitem__
,并且他们对未初始化的__map
属性的访问引发了错误:
So, when you called d['a']
= 1, in search of __setitem__
Python reached OrdereredDict's __setitem__
and their the access of uninitialized __map
attribute raised the error:
一种解决方法是显式调用defaultdict
和OrderedDict
上的__init__
:
A fix will be to call __init__
on both defaultdict
and OrderedDict
explicitly:
class DefaultOrderedDict(defaultdict, OrderedDict):
def __init__(self, default_factory=None, *a, **kw):
for cls in DefaultOrderedDict.mro()[1:-2]:
cls.__init__(self, *a, **kw)
这篇关于为什么不能通过继承OrderedDict和defaultdict创建默认的有序dict?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!