我可以在Python中执行有序的默认dict吗?

时间:2011-05-31 16:02:12

标签: python dictionary

我想将OrderedDict()defaultdict()中的collections合并到一个对象中,该对象应该是有序的默认字典。这可能吗?

9 个答案:

答案 0 :(得分:82)

以下(使用this recipe的修改版本)对我有用:

from collections import OrderedDict, Callable

class DefaultOrderedDict(OrderedDict):
    # Source: http://stackoverflow.com/a/6190500/562769
    def __init__(self, default_factory=None, *a, **kw):
        if (default_factory is not None and
           not isinstance(default_factory, Callable)):
            raise TypeError('first argument must be callable')
        OrderedDict.__init__(self, *a, **kw)
        self.default_factory = default_factory

    def __getitem__(self, key):
        try:
            return OrderedDict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)

    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = value = self.default_factory()
        return value

    def __reduce__(self):
        if self.default_factory is None:
            args = tuple()
        else:
            args = self.default_factory,
        return type(self), args, None, None, self.items()

    def copy(self):
        return self.__copy__()

    def __copy__(self):
        return type(self)(self.default_factory, self)

    def __deepcopy__(self, memo):
        import copy
        return type(self)(self.default_factory,
                          copy.deepcopy(self.items()))

    def __repr__(self):
        return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
                                               OrderedDict.__repr__(self))

答案 1 :(得分:36)

这是另一种可能性,受Raymond Hettinger's super() Considered Super启发,在Python 2.7.X和3.4.X上测试:

from collections import OrderedDict, defaultdict

class OrderedDefaultDict(OrderedDict, defaultdict):
    def __init__(self, default_factory=None, *args, **kwargs):
        #in python3 you can omit the args to super
        super(OrderedDefaultDict, self).__init__(*args, **kwargs)
        self.default_factory = default_factory

如果您查看班级的MRO(又名help(OrderedDefaultDict)),您会看到:

class OrderedDefaultDict(collections.OrderedDict, collections.defaultdict)
 |  Method resolution order:
 |      OrderedDefaultDict
 |      collections.OrderedDict
 |      collections.defaultdict
 |      __builtin__.dict
 |      __builtin__.object

意味着当OrderedDefaultDict的实例被初始化时,它会延迟到OrderedDict的init,但是这个实际上会在调用{{defaultdict之前调用__builtin__.dict的方法。 1}},这正是我们想要的。

答案 2 :(得分:19)

这是另一种解决方案,可以考虑您的用例是否与我的一样简单,并且您不一定要在代码中添加DefaultOrderedDict类实现的复杂性。

from collections import OrderedDict

keys = ['a', 'b', 'c']
items = [(key, None) for key in keys]
od = OrderedDict(items)

None是我想要的默认值。)

请注意,如果您的一个要求是使用默认值动态插入新密钥,则此解决方案无法正常工作。简单的权衡。

更新3/13/17 - 我了解了此用例的便利功能。与上面相同,但您可以省略行items = ...,只需:

od = OrderedDict.fromkeys(keys)

输出:

OrderedDict([('a', None), ('b', None), ('c', None)])

如果您的密钥是单个字符,您只需传递一个字符串:

OrderedDict.fromkeys('abc')

这与上面两个例子的输出相同。

您还可以将默认值作为第二个参数传递给OrderedDict.fromkeys(...)

答案 3 :(得分:14)

如果您想要一个不需要课程的简单解决方案,您可以使用OrderedDict.setdefault(key, default=None)OrderedDict.get(key, default=None)。如果你只是从几个地方获得/设置,比如循环,你可以很容易地设置默认。

totals = collections.OrderedDict()

for i, x in some_generator():
    totals[i] = totals.get(i, 0) + x

setdefault列表更容易:

agglomerate = collections.OrderedDict()

for i, x in some_generator():
    agglomerate.setdefault(i, []).append(x)

但如果你多次使用它,最好设置一个类,就像在其他答案中一样。

答案 4 :(得分:6)

@zeekay答案的简单版本是:

from collections import OrderedDict

class OrderedDefaultListDict(OrderedDict): #name according to default
    def __missing__(self, key):
        self[key] = value = [] #change to whatever default you want
        return value

答案 5 :(得分:3)

基于@NickBread的简单而优雅的解决方案。 有一个稍微不同的API来设置工厂,但良好的默认值总是很好。

class OrderedDefaultDict(OrderedDict):
    factory = list

    def __missing__(self, key):
        self[key] = value = self.factory()
        return value

答案 6 :(得分:2)

另一种简单的方法是使用字典get方法

>>> from collections import OrderedDict
>>> d = OrderedDict()
>>> d['key'] = d.get('key', 0) + 1
>>> d['key'] = d.get('key', 0) + 1
>>> d
OrderedDict([('key', 2)])
>>> 

答案 7 :(得分:0)

受此线程上其他答案的启发,您可以使用类似的

from collections import OrderedDict

class OrderedDefaultDict(OrderedDict):
    def __missing__(self, key):
        value = OrderedDefaultDict()
        self[key] = value
        return value

我想知道在 missing 方法中初始化同一个类的另一个对象是否有不利之处。

答案 8 :(得分:-1)

我测试了默认字典并发现它也已经排序了! 也许这只是一个巧合,但无论如何你可以使用排序函数:

sorted(s.items())

我觉得它更简单

相关问题