Search code examples
pythonpython-3.x

Python 3 superclass instantiation via derived class's default constructor


In this code:

class A():
  def __init__(self, x):
    self.x = x
  
  def __str__(self):
    return self.x

class B(A):
  def __str__(self):
    return super().__str__()

b = B("Hi")
print(b)

The output is: Hi.

What is happening under the hood? How does the default constructor in the derived class invoke the super class constructor? How are the params passed to the derived class object get mapped to those of the super class?


Solution

  • How does the default constructor in the derived class invoke the super class constructor?

    You didn't override it in B, so you inherited it from A. That's what inheritance is for.

    >>> B.__init__ is A.__init__
    True
    

    In the same vein, you may as well not define B.__str__ at all here, since it doesn't do anything (other than add a useless extra frame into the call stack).

    How are the params passed to the derived class object get mapped to those of the super class?

    You may be overthinking this. As shown above, B.__init__ and A.__init__ are identical. B.__init__ gets resolved in the namespace of A, since it is not present in the namespace of B.

    >>> B.__mro__
    (__main__.B, __main__.A, object)
    >>> A.__dict__["__init__"]
    <function __main__.A.__init__(self, x)>
    >>> B.__dict__["__init__"]
    ...
    # KeyError: '__init__'
    

    What is happening under the hood?

    Please note that __init__ methods are not constructors. If you're looking for an analogy of constructors in other programming languages, the __new__ method may be more suitable than __init__. First, an instance of B will created (by __new__), and then this instance will be passed as the first positional argument self to A.__init__, along with the string value "Hi" for the second positional argument x.