1

in this example :

class Dinosaur:
  def __init__(self, size, weight):
    self.size = size
    self.weight = weight
    
class Carnivore:
  def __init__(self, diet):
    self.diet = diet
    
class Tyrannosaurus(Dinosaur, Carnivore):
  def __init__(self, size, weight, diet):
    Dinosaur.__init__(self, size, weight)
    Carnivore.__init__(self, diet)
    
tiny = Tyrannosaurus(12, 14, "whatever it wants")

i have to mention "self" in both

    Dinosaur.__init__(self, size, weight)
    Carnivore.__init__(self, diet)

or i get an error.

but in single inheritance

class Person():
    def __init__(self, name, age, occupation):
        self.name = name
        self.age = age
        self.occupation = occupation

class Superhero(Person):
    def __init__(self, name, age, occupation, secret_identity):
        super().__init__(name, age, occupation)
        self.secret_identity = secret_identity

i didn't have to mention self in the init method

super().__init__(name, age, occupation)

i'm wondering what is exactly going on under the hood that returns from super().init(...) without mentioning "self"

and what is going on in multiple inheritance that i HAVE to use "self" or i get an error

brightstar2100
  • 117
  • 1
  • 8
  • This isn't the right way to write an `__init__` method with multiple inheritance. The proper way is for every class (including the base classes) to call `super().__init__` with all leftover arguments. See https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ – kaya3 Jul 31 '21 at 14:27

1 Answers1

1

It's not a matter of single-vs-multiple inheritance. It's the difference between hardcoding the class names vs using super.

Dinosaurs.__init__ is a specific reference to a function; no method object is created, and so nothing is implicitly wrapping the self argument and you have to supply it explicitly.

super().__init__, on the other hand, does produce a method argument that wraps self (which was, due to some compiler magic, treated as a default argument to super itself).

You could have used super in the multiple-inheritance example, in which case you would not have had to pass self as an explicit argument. In fact, super was invented to ease the definition of code that uses multiple inheritance.

class Dinosaur:
    def __init__(self, size, weight, **kwargs)
        super().__init__(**kwargs)
        self.size = size
        self.weight = weight
    
class Carnivore:
    def __init__(self, diet, **kwargs):
        super().__init__(**kwargs)
        self.diet = diet
    
class Tyrannosaurus(Dinosaur, Carnivore):
      pass

tiny = Tyrannosaurus(size=12, weight=14, diet="whatever it wants")

See https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ for an explanation of why I used keyword argument in this fashion, as well as why both Dinosaur and Carnivore call super.

kaya3
  • 47,440
  • 4
  • 68
  • 97
chepner
  • 497,756
  • 71
  • 530
  • 681