29

Subclassing a Python dict works as expected:

>>> class DictSub(dict):
...     def __init__(self):
...         self[1] = 10
...         
>>> DictSub()
{1: 10}

However, doing the same thing with a collections.OrderedDict does not work:

>>> import collections
>>> class OrdDictSub(collections.OrderedDict):
...     def __init__(self):
...         self[1] = 10
...         
>>> OrdDictSub()
(…)
AttributeError: 'OrdDictSub' object has no attribute '_OrderedDict__root'

Thus, the OrderedDict implementation uses a private __root atribute, which prevents the subclass OrdDictSub from behaving like the DictSub subclass. Why? How can one inherit from an OrderedDict?

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260

2 Answers2

36

You need to invoke OrderedDict.__init__ from your __init__:

class OrdDictSub(collections.OrderedDict):
    def __init__(self):
        super(OrdDictSub, self).__init__()

You haven't given OrderedDict a chance to initialize itself. Technically, you want to do this for your dict subclass as well, since you want a fully initialized dict. The fact that dict works without it is just luck.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • Thanks. My bad, indeed. It is true that I was influenced by dict. I even asked a question about dict some time ago (http://stackoverflow.com/questions/2033150/subclassing-dict-should-dict-init-be-called)! – Eric O. Lebigot Jun 24 '12 at 03:28
  • 7
    don't you want args and kwargs in init? `def __init__(self, *args, **kwargs): super(OrdDictSub, self).__init__(*args, **kwargs)` – hobs Feb 10 '13 at 06:00
  • You forgot to add the `*args, **kwds` and transfer them into the `__init__` method, but this answer is correct about the need to invoke `__init__`. – WhyWhat Jan 14 '23 at 09:21
2

Try initializing the superclass in the __init__ method:

def __init__(self):
    collections.OrderedDict.__init__(self)
    self[1] = 10

This is the normal way to initialize a subclass. You don't have to call the superclass's __init__ method in general, but if you have no knowledge of the superclass's implementation you really should call __init__.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 3
    Use `super()` to call methods of superclass – Aleksei astynax Pirogov Jun 24 '12 at 03:24
  • 10
    @DietrichEpp: Good answer, but using `super()` is not a matter of style: it is important to use it (instead of using an explicit superclass) in case your own class is subclassed. Example of reference: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/. Furthermore, using `super()` makes the code at tad easier to maintain (it is easier to change the name of the class). – Eric O. Lebigot Jun 24 '12 at 03:29
  • @EOL: I can accept that `super()` is the way to go, but I disagree with your "furthermore": I'd say it's six of one and half dozen of the other, *in Python 2*. If you want to change the name of your `OrdDictSub` class but still keep the same parent, then using `super()` means you have to do it in two places instead of just one. On the other hand, if you want to keep the `OrdDictSub` name but change the parent, then *not* using `super()` means you have to do it in two places rather than one. Fortunately, this was fixed in Python 3 (just call `super()` without parameters). – John Y Jun 27 '14 at 15:55
  • @JohnY: Agreed, about `super()` not being more convenient in case of class name changes in Python 2, but only in Python 3. – Eric O. Lebigot Jun 28 '14 at 02:55
  • @JohnY: Well, I tested it, and using `self.__class__` is wrong, because `self.__class__` always gives the actual class! Here is a demo you can try yourself, it will throw a `RuntimeError` when it exceeds the maximum recursion depth: https://gist.github.com/depp/87a5f1079556eb0ed07e – Dietrich Epp Nov 07 '14 at 22:07
  • @JohnY: But you can only know that it's safe if you know that your class will never be subclassed, which I don't think is a very good assumption most of the time. – Dietrich Epp Nov 07 '14 at 22:30
  • @JohnY: It's incorrect to say that if you use `super()`, others are screwed if they don't. You can mix `super()` and direct base class calls just fine, as long as you don't do this in a class with multiple paths to a base class (in which case you *have* to use `super()`). The only one that always breaks in common cases is `super(self.__class__, self)`, which is why you shouldn't use it. – Dietrich Epp Nov 08 '14 at 09:18
  • 1
    @JohnY: This excellent answer by Martijn Pieters covers it: http://stackoverflow.com/a/18208725/82294 -- if you think Martijn is wrong, go argue over there. – Dietrich Epp Nov 08 '14 at 09:20
  • @DietrichEpp: OK, fair enough. It is indeed a very nice explanation by Martijn. I've removed some of my comments here, as I believe they are not helpful to future readers, even in a historical capacity (except to serve as evidence of my ignorance). – John Y Nov 08 '14 at 10:08