We can create an OrderedCounter
trivially by using multiple inheritance:
>>> from collections import Counter, OrderedDict
>>> class OrderedCounter(Counter, OrderedDict):
... pass
...
>>> OrderedCounter('Mississippi').items()
[('M', 1), ('i', 4), ('s', 4), ('p', 2)]
Correct me if I'm wrong, but this crucially relies on the fact that Counter
uses super
:
class Counter(dict):
def __init__(*args, **kwds):
...
super(Counter, self).__init__()
...
That is, the magic trick works because
>>> OrderedCounter.__mro__
(__main__.OrderedCounter,
collections.Counter,
collections.OrderedDict,
dict,
object)
The super
call must delegate according to 'siblings before parents' rule of the mro, whence the custom class uses an OrderedDict
as the storage backend.
However a colleague recently pointed out, to my surprise, that OrderedDict
doesn't use super:
def __setitem__(self, key, value,
dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
...
# <some weird stuff to maintain the ordering here>
dict_setitem(self, key, value)
At first I thought it could be because OrderedDict
came first and Raymond didn't bother to change it later, but it seems that super
predates OrderedDict
.
Why does OrderedDict
call dict.__setitem__
explicitly?
And why does it need to be a kwarg? Doesn't this cause trouble when using OrderedDict
in diamond inheritance situations, since it passes directly to the parent class instead of delegating to the next in line in the mro?