我们可以创建一个OrderedCounter
简单地通过使用多重继承:
>>> from collections import Counter, OrderedDict
>>> class OrderedCounter(Counter, OrderedDict):
... pass
...
>>> OrderedCounter('Mississippi').items()
[('M', 1), ('i', 4), ('s', 4), ('p', 2)]
如果我错了,请纠正我,但这关键取决于以下事实:Counter uses super https://github.com/python/cpython/blob/761d139852063b9aa3caf58023184c4a399d594f/Lib/collections/__init__.py#L533:
class Counter(dict):
def __init__(*args, **kwds):
...
super(Counter, self).__init__()
...
也就是说,这个魔术之所以有效,是因为
>>> OrderedCounter.__mro__
(__main__.OrderedCounter,
collections.Counter,
collections.OrderedDict,
dict,
object)
The super
呼叫必须根据“兄弟姐妹先于父母”的规则进行委派mro https://www.python.org/download/releases/2.3/mro/,因此自定义类使用OrderedDict
作为存储后端。
然而,令我惊讶的是,最近一位同事指出,OrderedDict
doesn't https://github.com/python/cpython/blob/761d139852063b9aa3caf58023184c4a399d594f/Lib/collections/__init__.py#L107-L119使用超级:
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)
起初我以为这可能是因为OrderedDict
先来的,雷蒙德后来也懒得去改,但看起来super
早于OrderedDict
.
为什么OrderedDict
call dict.__setitem__
明确地?
为什么它需要是一个 kwarg?这在使用时不会造成麻烦吗OrderedDict
在钻石继承的情况下,因为它直接传递给父类而不是委托给 mro 中的下一个?