我可以在Python中做一个有序的默认字典吗?

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

以下(使用这个配方的修改版本)为我工作:

 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)) 

这是另一种可能性,由Raymond Hettinger的super()Considered Super在Python 2.7.X和3.4.X上testing:

 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(aka, help(OrderedDefaultDict) ),您将看到:

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

这意味着当OrderedDefaultDict一个实例被初始化时,它依照OrderedDict的init,但是这个在调用__builtin__.dict之前会调用defaultdict的方法,这正是我们想要的。

如果你的用例和我的一样简单,你不需要将DefaultOrderedDict类实现的复杂性添加到你的代码中,这里有另一种解决scheme。

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

None是我想要的默认值。)

请注意,如果您的要求之一是dynamic地插入具有默认值的新密钥,则此解决scheme将不起作用。 简单的权衡。

17/17/17更新 – 我学习了这个用例的一个便利函数。 与上面相同,但您可以省略订单items = ...并且只是:

 od = OrderedDict.fromkeys(keys) 

输出:

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

如果你的键是单个字符,你可以传递一个string:

 OrderedDict.fromkeys('abc') 

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

您可以将默认值作为第二个parameter passing给OrderedDict.fromkeys。

如果你想要一个不需要类的简单解决scheme,你可以使用OrderedDict. setdefault ( key, default=None ) OrderedDict. setdefault ( key, default=None )OrderedDict. get ( 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) 

但是,如果你使用它不止几次,build立一个class级可能会更好,就像其他答案一样。

更简单的@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