3

I am following a tutorial online and the code is this:

class Hands(list):
    def __init__(self, size=0, die_class=None, *args, **kwargs):
        if not die_class:
            raise ValueError("You must provide a die class")
        super().__init__()

        for _ in range(size):
            self.append(die_class())

It basically models a player with a number of dice (size) and what dice they are holding (die_class).

My confusion is why do we need to call super().__init__? I tried running the code without it and it worked fine! Why is the call necessary?

quamrana
  • 37,849
  • 12
  • 53
  • 71
Brendon Cheung
  • 995
  • 9
  • 29
  • 1
    even if it works now because `list` doesn't seem to need a default constructor, what if the next python versions require `__init__` to be called on a `list` object? why _not_ calling `__init__` ? – Jean-François Fabre Sep 20 '17 at 14:24
  • It's not necessary (but it's good practice), see https://softwareengineering.stackexchange.com/questions/318165/is-calling-the-superclass-constructor-in-a-subclass-really-important – Paco H. Sep 20 '17 at 14:24
  • I think it breaks Liskov principle. it works, okay, but when will it break? – Jean-François Fabre Sep 20 '17 at 14:26
  • 1
    Possible duplicate of [Subclassing dict: should dict.\_\_init\_\_() be called?](https://stackoverflow.com/questions/2033150/subclassing-dict-should-dict-init-be-called) – quamrana Sep 20 '17 at 15:35

2 Answers2

2

You need to call the __init__() if the base class to be sure any initialisation code there is run. That it (seems) to work without that call can be a coincidence, or you may simply haven't hit the resulting problem yet. Even if it works consistently in the Python version and implementation you are using currently, it isn't guaranteed for other versions and implementations to work without calling the base class' __init__ method.

Also you can actually use that call to populate the list with your dice objects:

class Hands(list):
    def __init__(self, size=0, die_factory=None):
        if not die_factory:
            raise ValueError('You must provide a die factory')
        super().__init__(die_factory() for _ in range(size))

I've renamed die_class to die_factory as any callable that produces a new die object can be used here.

Note: You may violate the is-a relationship between Hands and list here unless a Hands object actually is a list, i.e. all methods and behaviour of lists also make sense for Hands objects.

BlackJack
  • 4,476
  • 1
  • 20
  • 25
-1

super() lets you avoid referring to the base class explicitly. More importantly, with multiple inheritance, you can do stuff like this. At the end of the day, it is not necessary, it's just good practice.

liam
  • 1,918
  • 3
  • 22
  • 28