为什么不能通过继承OrderedDict和defaultdict创建默认的有序dict? [英] Why can't I create a default, ordered dict by inheriting OrderedDict and defaultdict?

查看:117
本文介绍了为什么不能通过继承OrderedDict和defaultdict创建默认的有序dict?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我首先尝试在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:

一种解决方法是显式调用defaultdictOrderedDict上的__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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆