通过(2行长)多重继承实现的OrderedCounter
在Raymond Hettinger精彩演讲超越考虑中,我们可以使用多重继承:
from collections import OrderedDict, Counter
class OrderedCounter(Counter, OrderedDict):
pass
并使用它:
>>> counter = OrderedCounter("abracadabra")
>>> for key, value in counter.items():
... print key, value
a 5
b 2
r 2
c 1
d 1
这就是你完成任务所需要的全部。
修复有点混乱的表示
让我们进行更多的测试,看看我们得到了什么“结果”:
>>> counter = OrderedCounter("cbaaa")
>>> counter
OrderedCounter({'a': 3, 'c': 1, 'b': 1})
哦- 看起来不对,期望的顺序应该是 "c","b","a"。让我们通过打印键和值来测试它:
>>> for key, value in counter.items():
... print key, value
c 1
b 1
a 3
这看起来是正确的(并且完全符合在您的代码中使用的要求)。
事实证明,我们创建的类只是产生了一种有点令人困惑的表示形式。
这可以修复:
class OrderedCounter(Counter, OrderedDict):
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, OrderedDict(self))
当使用时:
>>> counter = OrderedCounter("cbaaa")
>>> counter
OrderedCounter({'c': 1, 'b': 1, 'a': 1})
来自Raymond Hettinger演讲的完整版本(添加了pickling)
演讲中提供的完整版本添加了一个方法__reduce__
,允许正确地进行pickling对象。
from collections import OrderedDict, Counter
class OrderedCounter(Counter, OrderedDict):
"""Counter that remembers the order elements are first seen"""
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
无论如何,在大多数情况下,您只需使用最简单版本的OrderedCounter
类即可完成。