1

I have tried inheriting from both collections.defaultdict and collections.OrderedDict like so:

class OrderedDefaultDict(defaultdict, OrderedDict): pass

and like so:

class OrderedDefaultDict(OrderedDict, defaultdict): pass

in order to created an ordered default dict (a class that should remember the order in which new default items were generated) but it seems to throw an error stating:

TypeError: multiple bases have instance lay-out conflict

I have read here that it's because they're both implemented in C. Upon disabling Python's C implementation of OrderedDict by commenting this section in the collections module:

try:
    from _collections import OrderedDict
except ImportError:
    # Leave the pure Python version in place.
    pass

I have managed to inherit from both, but it does not seem to work as I expected. I have two questions then:

  1. Why can't you inherit from two classes written in C? I would understand if you wouldn't be able to inherit from any class written in C but why can you inherit from one and not from 2?
  2. Implementing my requested class would be easy by subclassing OrderedDict and overriding __getitem__() to match defaultdict's behavior. Is there a better way (preferably within the standard library) to mimick the same behavior? Or is subclassing OrderedDict the most optimal? (subclassing defaultdict is possible too but implementing it is is probably easier using OrderedDict)

The first question is the important of the two as implementing it myself by subclassing OrderedDict shouldn't pose a problem.

Community
  • 1
  • 1
Bharel
  • 23,672
  • 5
  • 40
  • 80
  • 1
    I think you'd be better off subclassing `OrderedDict` and defining a [`__missing__`](https://docs.python.org/2/reference/datamodel.html#object.__missing__) method. – Two-Bit Alchemist Apr 19 '16 at 19:41
  • I think if your edit is true wrt what "the important part" of your question is, then it's a duplicate. You've misread the answer you linked. The point isn't that they're implemented in C. The point is that they're internally incompatible (though the C implementation makes that more possible/likely) so there's no way for Python to automatically use them for multiple inheritance. – Two-Bit Alchemist Apr 19 '16 at 20:10
  • @Two-BitAlchemist Why would they be internally incompatible? Classes in the STL usually talk with themselves nicely like `OrderedDict` and `Counter` for example. – Bharel Apr 19 '16 at 20:13
  • That's a better question for the Python mailing list than for me. Wild guess: they're both subsets of dict written in C and no effort was made to give them a similar API because they're not similar in function. – Two-Bit Alchemist Apr 19 '16 at 20:16
  • See the `OrderedDefaultdict` class in [this answer](http://stackoverflow.com/a/4127426/355230). – martineau Apr 19 '16 at 20:31

1 Answers1

4

The functionality of defaultdict can be simply implemented by defining a __missing__ method:

class DefaultOrderedDict(OrderedDict):
    def __init__(self, default_factory=None, **kwargs):
        OrderedDict.__init__(self, **kwargs)
        self.default_factory = default_factory

    def __missing__(self, key):
        result = self[key] = self.default_factory()
        return result
Daniel
  • 42,087
  • 4
  • 55
  • 81
  • I think I'd want to make the `__init__` a little more robust than this. You're losing a lot of `dict` functionality this way. – Two-Bit Alchemist Apr 19 '16 at 19:49
  • agreed. just use the `__init__` from defaultdict: `def __init__(self, default_factory=None, **kwargs):` – acushner Apr 19 '16 at 19:55
  • @acushner: agreed. – Daniel Apr 19 '16 at 20:04
  • @Daniel just on a side note, it's always funny when people use `**kwargs` with an `OrderedDict`, because those `kwargs` themselves aren't necessarily in any particular order. but it is still usable. nice update to the answer. – acushner Apr 20 '16 at 20:01