0

EDIT: According to this answer, it's a good idea to call super(), because otherwise behavior might be undefined. I suppose my question in that case really is, how is it that my code works even without calling it? That would seem like a light switch working without anyone hooking up the electricity. So I'm more interested in the mechanics of what's going on, and not a simple "yes add it" or "no it's not necessary".

I'm working with the following python code to implement an LRU cache. It subclasses OrderedDict in order to support the methods for the cache, namely get and put. It works perfectly, but I'm confused-- why don't I need to call the parent's constructor?

According to this answer, I should have to call super().__init__(), but I don't (try for yourself).

My question is, by what mechanism does my subclass know how to insert values into itself, if nothing was initialized?

from collections import OrderedDict

class LRUCache(OrderedDict):
    def __init__(self, capacity):
        self.capacity = capacity

    def get(self, key):
        if key not in self:
            return -1
        self.move_to_end(key)
        return self[key]

    def put(self, key, value):
        if key in self:
            self.move_to_end(key)
        elif len(self) == self.capacity:
            self.popitem(last=False)
        self[key] = value
sonarforte
  • 1,588
  • 15
  • 18

2 Answers2

1

OrderedDict is based on C code where the heavy lifting for initializing the underlying data structures is done during object construction, before __init__. It so happens that __init__ in this case is only concerned with how initialization parameters are handled. If you don't need that functionality, you can skip calling super .... at the risk of introducing bugs somewhere down the line if the super class changes what it does in __init__.

tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

You need to call super().__init__() if you want the functionality that the dict initializer provides (initializing the dictionary from another dictionary or a sequence of key-value pairs). You're not using that functionality, so no harm in not calling it. Of course the other methods work; why would they not? The dictionary exists, it's just empty.

kindall
  • 178,883
  • 35
  • 278
  • 309
  • 1
    Generally, python objects need their initializers. In this case, `dict` is implemented in C so its setup happens before its `__init__` but any class that depends on state setup by `__init__` will not fare so well. – tdelaney Feb 26 '20 at 03:56
  • "You need to call `super().__init__()` if you want the functionality that the `dict` initializer provides (initializing the dictionary from another dictionary or a sequence of key-value pairs)." - it's not obvious (and not a documented guarantee) that that's the only functionality `dict.__init__` or `OrderedDict.__init__` performs. Typical classes implemented in Python need their `__init__` to be called for the object's internal data structures to exist at all. – user2357112 Feb 26 '20 at 03:59
  • @tdelaney I think that's the answer I was looking for. I'm not sure what the implementation specifics are, but it would seem that in order to do something like `cache = LRUCache(); cache[4]=3`, some amount of initialization had to take place. I.e., the bracket notation wouldn't work unless something told the interpreter that it's allowed. If it's implemented before the init method is called, then that makes sense. – sonarforte Feb 26 '20 at 04:00
  • (In fact, older versions of `OrderedDict` *did* require `OrderedDict.__init__` to be called for the object to work.) – user2357112 Feb 26 '20 at 04:01
  • @user2357112supportsMonica interesting, what changed? – sonarforte Feb 26 '20 at 04:02
  • @sonarforte - I tried to explain it in another answer. Hope it makes sense! – tdelaney Feb 26 '20 at 04:04