我可以在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