Why doesn't OrderedDict use super?

2019-03-31 04:48发布

问题:

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?

回答1:

It's a microoptimization. Looking up a dict_setitem argument is slightly faster than looking up dict.__setitem__ or super().__setitem__.

This might cause problems with multiple inheritance if you have another class that overrides __setitem__, but OrderedDict isn't designed for that kind of diamond-structured method overriding anyway. For OrderedDict to support that, it'd have to make very careful guarantees about what another class's methods might see if they try to index the OrderedDict while the ordering information is inconsistent with the dict structure. Such guarantees would be way too messy to make.