185

Why did the Python designers decide that subclasses' __init__() methods don't automatically call the __init__() methods of their superclasses, as in some other languages? Is the Pythonic and recommended idiom really like the following?

class Superclass(object):
    def __init__(self):
        print 'Do something'

class Subclass(Superclass):
    def __init__(self):
        super(Subclass, self).__init__()
        print 'Do something else'
martineau
  • 119,623
  • 25
  • 170
  • 301
jrdioko
  • 32,230
  • 28
  • 81
  • 120

11 Answers11

185

The crucial distinction between Python's __init__ and those other languages constructors is that __init__ is not a constructor: it's an initializer (the actual constructor (if any, but, see later;-) is __new__ and works completely differently again). While constructing all superclasses (and, no doubt, doing so "before" you continue constructing downwards) is obviously part of saying you're constructing a subclass's instance, that is clearly not the case for initializing, since there are many use cases in which superclasses' initialization needs to be skipped, altered, controlled -- happening, if at all, "in the middle" of the subclass initialization, and so forth.

Basically, super-class delegation of the initializer is not automatic in Python for exactly the same reasons such delegation is also not automatic for any other methods -- and note that those "other languages" don't do automatic super-class delegation for any other method either... just for the constructor (and if applicable, destructor), which, as I mentioned, is not what Python's __init__ is. (Behavior of __new__ is also quite peculiar, though really not directly related to your question, since __new__ is such a peculiar constructor that it doesn't actually necessarily need to construct anything -- could perfectly well return an existing instance, or even a non-instance... clearly Python offers you a lot more control of the mechanics than the "other languages" you have in mind, which also includes having no automatic delegation in __new__ itself!-).

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 8
    Upvoted because for me, the real benefit is the ability you mention to call the superclass's \__init()\__ at any point in the subclass's initialization (or not at all). – kindall Sep 23 '10 at 22:35
  • 73
    -1 for "`__init__` is not a constructor... the actual constructor ... is `__new__`". As you yourself note, `__new__` behaves nothing like a constructor from other languages. `__init__` is in fact very similar (it is called during the creation of a new object, **after** that object is allocated, to set member variables on the new object), and is almost always the place to implement functionality that in other languages you would put in a constructor. So just call it a constructor! – Ben Oct 31 '11 at 00:36
  • 13
    I also think this is a rather absurd statement: "**constructing** all superclasses ... is obviously part of saying you're **constructing** a subclass's instance, that is clearly not the case for **initializing**". There is nothing in the words construction/initialization that makes this "obvious" to anyone. And `__new__` doesn't automatically invoke superclass `__new__` either. So your claim that the key distinction is that **construction** necessarily involves the construction of superclasses, while **initialization** does not is inconsistent with your claim that `__new__` is the constructor. – Ben Oct 31 '11 at 00:38
  • 48
    In fact, from the python docs for `__init__` at http://docs.python.org/reference/datamodel.html#basic-customization : "As a special constraint on **constructors**, no value may be returned; doing so will cause a TypeError to be raised at runtime" (emphasis mine). So there, it's official, `__init__` is a constructor. – Ben Oct 31 '11 at 01:18
  • 6
    In Python/Java terminology, `__init__` is called a constructor. This constructor is an initialization function called after the object has been completely constructed and initialized to a default state including its final runtime type. It is not equivalent to C++ constructors, that are called on a statically typed, allocated object with an undefined state. These are also different from `__new__`, so we really have at least four different kinds of allocation/construction/initialization functions. Languages uses mixed terminology, and the important part is the behavior and not the terminology. – Elazar Jan 13 '17 at 13:06
  • 1
    I do think that Python gives you more control and freedom, but this is not necessarily a good thing, and I would even say that (in this case) it's not even a good thing, because it's not an intuitive way of facing OOP, since it goes against the comparison that one usually does (when programming in a OO way) with the real world. Actually I wonder if this was made on purpose when designing the language, given that, apparently (from what I've been reading), Guido was not really a strong admirer of the OO paradigm at the time. With Python clearly you can break easily what you think is inheritance. – nbro Feb 14 '17 at 01:11
  • 5
    "Constructor" vs. "initializer" is a distinction without a difference. The user-written part of any constructor in any OOP language is initialization. – Mike Housky Aug 12 '18 at 12:28
  • In languages that let you modify allocation (e.g. C++), a constructor *only* does initialisation. In languages that don't (e.g. Java), you can't distinguish between "the runtime allocates then the constructor initialises" and "the constructor allocates and initialises" – Caleth Aug 07 '19 at 13:26
  • @MikeHousky It's absolutely a valid distinction, just not the one you think it is. `__new__` is *responsible* for producing the object to be returned, whether it grabs a pre-existing instance or defers to `object.__new__` to create a truly new instance. `__new__` is called first, and determines whether `__init__` even *will* be called. `__init__` does not return anything; it can only work with the object it receives as an argument. – chepner Jul 27 '21 at 17:53
  • @chepner The main reason for `__new__` is to allow subclasses to customize initialization of an immutable base class object. None of this language of yours is in the Language Reference manual (which doesn't call either `__new__` or `__init__` a "constructor" or "initializer") and it's all still initialization (yes...even memory allocation, if you could actually do that). None of this applies to OP's question, anyway. – Mike Housky Jul 29 '21 at 05:24
37

I'm somewhat embarrassed when people parrot the "Zen of Python", as if it's a justification for anything. It's a design philosophy; particular design decisions can always be explained in more specific terms--and they must be, or else the "Zen of Python" becomes an excuse for doing anything.

The reason is simple: you don't necessarily construct a derived class in a way similar at all to how you construct the base class. You may have more parameters, fewer, they may be in a different order or not related at all.

class myFile(object):
    def __init__(self, filename, mode):
        self.f = open(filename, mode)
class readFile(myFile):
    def __init__(self, filename):
        super(readFile, self).__init__(filename, "r")
class tempFile(myFile):
    def __init__(self, mode):
        super(tempFile, self).__init__("/tmp/file", mode)
class wordsFile(myFile):
    def __init__(self, language):
        super(wordsFile, self).__init__("/usr/share/dict/%s" % language, "r")

This applies to all derived methods, not just __init__.

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • 8
    Does this example offer something special? static languages can do this also – jean Nov 07 '15 at 02:36
  • 2
    And so? How does it prevent the default (no parameter) superclass constructor from being called implicitly? That is what the other languages do (C++, Java, etc.). – Géry Ogam Jul 26 '20 at 10:07
23

Java and C++ require that a base class constructor is called because of memory layout.

If you have a class BaseClass with a member field1, and you create a new class SubClass that adds a member field2, then an instance of SubClass contains space for field1 and field2. You need a constructor of BaseClass to fill in field1, unless you require all inheriting classes to repeat BaseClass's initialization in their own constructors. And if field1 is private, then inheriting classes can't initialise field1.

Python is not Java or C++. All instances of all user-defined classes have the same 'shape'. They're basically just dictionaries in which attributes can be inserted. Before any initialisation has been done, all instances of all user-defined classes are almost exactly the same; they're just places to store attributes that aren't storing any yet.

So it makes perfect sense for a Python subclass not to call its base class constructor. It could just add the attributes itself if it wanted to. There's no space reserved for a given number of fields for each class in the hierarchy, and there's no difference between an attribute added by code from a BaseClass method and an attribute added by code from a SubClass method.

If, as is common, SubClass actually does want to have all of BaseClass's invariants set up before it goes on to do its own customisation, then yes you can just call BaseClass.__init__() (or use super, but that's complicated and has its own problems sometimes). But you don't have to. And you can do it before, or after, or with different arguments. Hell, if you wanted you could call the BaseClass.__init__ from another method entirely than __init__; maybe you have some bizarre lazy initialization thing going.

Python achieves this flexibility by keeping things simple. You initialise objects by writing an __init__ method that sets attributes on self. That's it. It behaves exactly like a method, because it is exactly a method. There are no other strange and unintuitive rules about things having to be done first, or things that will automatically happen if you don't do other things. The only purpose it needs to serve is to be a hook to execute during object initialisation to set initial attribute values, and it does just that. If you want it to do something else, you explicitly write that in your code.

Ben
  • 68,572
  • 20
  • 126
  • 174
  • 2
    As for C++, it has nothing to do with the "memory layout". The same initialization model as Python offers could have been implemented in C++. The only reason why construction/destruction are the way they are in C++ is because of the design decision to provide reliable and well-behaving facilities for resource management (RAII), which could as well be automagically generated (meaning less code and human errors) by compilers since the rules for them (their call order) are rigorously defined. Not sure but Java most likely simply followed this approach to be yet another POLA C-like language. – Alexander Shukaev Nov 12 '18 at 23:41
  • 2
    I think it's an F-ed up choice, but +1 for explaining it conherently. – Tony Delroy May 05 '21 at 13:57
18

To avoid confusion it is useful to know that you can invoke the base_class __init__() method if the child_class does not have an __init__() class.

Example:

class parent:
  def __init__(self, a=1, b=0):
    self.a = a
    self.b = b

class child(parent):
  def me(self):
    pass

p = child(5, 4)
q = child(7)
z= child()

print p.a # prints 5
print q.b # prints 0
print z.a # prints 1

In fact the MRO in python will look for __init__() in the parent class when can not find it in the children class. You need to invoke the parent class constructor directly if you have already an __init__() method in the children class.

For example the following code will return an error: class parent: def init(self, a=1, b=0): self.a = a self.b = b

    class child(parent):
      def __init__(self):
        pass
      def me(self):
        pass

    p = child(5, 4) # Error: constructor gets one argument 3 is provided.
    q = child(7)  # Error: constructor gets one argument 2 is provided.

    z= child()
    print z.a # Error: No attribute named as a can be found.
Mike Housky
  • 3,959
  • 1
  • 17
  • 31
Keyvanrm
  • 283
  • 2
  • 3
  • 1
    The key point is that [__init__] will be called only once, the lowest one in the inheritance tree search during an instance instantiation. If there are superclass [__init__] you want to call, you have to explicitly call them with super().__init__() recursively. If there is no [__init__] defined along the tree path, nothing will be called. It is just an ordinary function that is automatically called once at construction time. You can later invoke it with something like child.__init__(p, 4, 5). – Leon Chang Oct 14 '20 at 03:06
  • 1
    Is this documented in the Python docs? I found [`object.__init__()`](https://docs.python.org/3/reference/datamodel.html#object.__init__) and read "If a base class has an `__init__()` method, the derived class’s `__init__()` method, if any, must explicitly call it to ensure proper initialization of the base class part of the instance". But that does not specify the behavior when a derived class lacks an `__init__()`. – ogdenkev Sep 30 '21 at 19:34
  • @ogdenkev The "if any" in your quote subtly signalizes that the subclass does not have to have an `__init__` method. – Jeyekomon Apr 29 '22 at 10:52
  • This one answer is worth more than all of the documentation for MRO (https://www.python.org/download/releases/2.3/mro/) and `object.__init__()`. Incidentally, if one wants to emulate an `__init__()` in a subclass without overloading the parent `__init__`, a `main() `(or whatever other name, doesn't matter) method can be defined and called from `__init__()` in the base and then overloaded in a child class. The overloaded `main()` method from the child class will be run by its call in the base parent init instead. – ChrisN Jul 15 '22 at 18:43
11

"Explicit is better than implicit." It's the same reasoning that indicates we should explicitly write 'self'.

I think in in the end it is a benefit-- can you recite all of the rules Java has regarding calling superclasses' constructors?

Mike Axiak
  • 11,827
  • 2
  • 33
  • 49
  • 9
    I agree with you for the most part, but Java's rule is actually pretty simple: the no-arg constructor is invoked unless you specifically ask for a different one. – Laurence Gonsalves Sep 23 '10 at 22:18
  • 2
    @Laurence - What happens when the parent class does not define a no-arg constructor? What happens when the no-arg constructor is protected or private? – Mike Axiak Sep 23 '10 at 22:34
  • 9
    Exactly the same thing that would happen if you tried to call it explicitly. – Laurence Gonsalves Sep 23 '10 at 22:50
8

Right now, we have a rather long page describing the method resolution order in case of multiple inheritance: http://www.python.org/download/releases/2.3/mro/

If constructors were called automatically, you'd need another page of at least the same length explaining the order of that happening. That would be hell...

viraptor
  • 33,322
  • 10
  • 107
  • 191
  • This was the right answer. Python would need to define semantics of argument passing between subclass and superclass. Too bad this answer is not upvoted. Maybe if it showed the problem with some examples? – Gary Weiss Sep 06 '17 at 12:41
  • This is AN answer and thanks for the link, but it's not a valid reasoning to proclaim "you'd have to ____..." when describing a what-if scenario in response to a very important question. The fact that it "would be hell" to explain the order of inheritance and instantiation given the current implementation if any different approach were followed says that there's too much magic behind the scenes, and the implementation is contrived and shortcomings excused rather than addressed. – ChrisN Jul 15 '22 at 20:42
  • @ChrisN I suppose the Proper Elegant Solutions will have to wait for Python 4 :) – Jeremy Friesner Jul 24 '23 at 21:45
7

Often the subclass has extra parameters which can't be passed to the superclass.

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • And so? How does it prevent the default (no parameter) superclass constructor from being called implicitly? That is what the other languages do (C++, Java, etc.). – Géry Ogam Jul 26 '20 at 10:03
3

Maybe __init__ is the method that the subclass needs to override. Sometimes subclasses need the parent's function to run before they add class-specific code, and other times they need to set up instance variables before calling the parent's function. Since there's no way Python could possibly know when it would be most appropriate to call those functions, it shouldn't guess.

If those don't sway you, consider that __init__ is Just Another Function. If the function in question were dostuff instead, would you still want Python to automatically call the corresponding function in the parent class?

Kirk Strauser
  • 30,189
  • 5
  • 49
  • 65
2

i believe the one very important consideration here is that with an automatic call to super.__init__(), you proscribe, by design, when that initialization method is called, and with what arguments. eschewing automatically calling it, and requiring the programmer to explicitly do that call, entails a lot of flexibility.

after all, just because class B is derived from class A does not mean A.__init__() can or should be called with the same arguments as B.__init__(). making the call explicit means a programmer can have e.g. define B.__init__() with completely different parameters, do some computation with that data, call A.__init__() with arguments as appropriate for that method, and then do some postprocessing. this kind of flexibility would be awkward to attain if A.__init__() would be called from B.__init__() implicitly, either before B.__init__() executes or right after it.

flow
  • 3,624
  • 36
  • 48
1

As Sergey Orshanskiy pointed out in the comments, it is also convenient to write a decorator to inherit the __init__ method.

You can write a decorator to inherit the __init__ method, and even perhaps automatically search for subclasses and decorate them. – Sergey Orshanskiy Jun 9 '15 at 23:17

Part 1/3: The implementation

Note: actually this is only useful if you want to call both the base and the derived class's __init__ since __init__ is inherited automatically. See the previous answers for this question.

def default_init(func):
    def wrapper(self, *args, **kwargs) -> None:
        super(type(self), self).__init__(*args, **kwargs)
    return wrapper

class base():
    def __init__(self, n: int) -> None:
        print(f'Base: {n}')

class child(base):
    @default_init
    def __init__(self, n: int) -> None:
        pass
        
child(42)

Outputs:

Base: 42

Part 2/3: A warning

Warning: this doesn't work if base itself called super(type(self), self).

def default_init(func):
    def wrapper(self, *args, **kwargs) -> None:
        '''Warning: recursive calls.'''
        super(type(self), self).__init__(*args, **kwargs)
    return wrapper

class base():
    def __init__(self, n: int) -> None:
        print(f'Base: {n}')

class child(base):
    @default_init
    def __init__(self, n: int) -> None:
        pass
        
class child2(child):
    @default_init
    def __init__(self, n: int) -> None:
        pass
        
child2(42)

RecursionError: maximum recursion depth exceeded while calling a Python object.

Part 3/3: Why not just use plain super()?

But why not just use the safe plain super()? Because it doesn't work since the new rebinded __init__ is from outside the class, and super(type(self), self) is required.

def default_init(func):
    def wrapper(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
    return wrapper

class base():
    def __init__(self, n: int) -> None:
        print(f'Base: {n}')

class child(base):
    @default_init
    def __init__(self, n: int) -> None:
        pass
        
child(42)

Errors:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-9-6f580b3839cd> in <module>
     13         pass
     14 
---> 15 child(42)

<ipython-input-9-6f580b3839cd> in wrapper(self, *args, **kwargs)
      1 def default_init(func):
      2     def wrapper(self, *args, **kwargs) -> None:
----> 3         super().__init__(*args, **kwargs)
      4     return wrapper
      5 

RuntimeError: super(): __class__ cell not found
user26742873
  • 919
  • 6
  • 21
0

Background - We CAN AUTO init a parent AND child class!

A lot of answers here and say "This is not the python way, use super().__init__() from the subclass". The question is not asking for the pythonic way, it's comparing to the expected behavior from other languages to python's obviously different one.

The MRO document is pretty and colorful but it's really a TLDR situation and still doesn't quite answer the question, as is often the case in these types of comparisons - "Do it the Python way, because.".

Inherited objects can be overloaded by later declarations in subclasses, a pattern building on @keyvanrm's (https://stackoverflow.com/a/46943772/1112676) answer solves the case where I want to AUTOMATICALLY init a parent class as part of calling a class without explicitly calling super().__init__() in every child class.

In my case where a new team member might be asked to use a boilerplate module template (for making extensions to our application without touching the core application source) which we want to make as bare and easy to adopt without them needing to know or understand the underlying machinery - to only need to know of and use what is provided by the application's base interface which is well documented.

For those who will say "Explicit is better than implicit." I generally agree, however, when coming from many other popular languages inherited automatic initialization is the expected behavior and it is very useful if it can be leveraged for projects where some work on a core application and others work on extending it.

This technique can even pass args/keyword args for init which means pretty much any object can be pushed to the parent and used by the parent class or its relatives.

Example:


class Parent:
    def __init__(self, *args, **kwargs):
        self.somevar = "test"
        self.anothervar = "anothertest"

        #important part, call the init surrogate pass through args:
        self._init(*args, **kwargs)

    #important part, a placeholder init surrogate:
    def _init(self, *args, **kwargs):
        print("Parent class _init; ", self, args, kwargs)

    def some_base_method(self):
        print("some base method in Parent")
        self.a_new_dict={}


class Child1(Parent):
    # when omitted, the parent class's __init__() is run
    #def __init__(self):
    #    pass

    #overloading the parent class's  _init() surrogate
    def _init(self, *args, **kwargs):
        print(f"Child1 class _init() overload; ",self, args, kwargs)

        self.a_var_set_from_child = "This is a new var!"


class Child2(Parent):
    def __init__(self, onevar, twovar, akeyword):
        print(f"Child2 class __init__() overload; ", self)

        #call some_base_method from parent
        self.some_base_method()

        #the parent's base method set a_new_dict
        print(self.a_new_dict)


class Child3(Parent):
    pass


print("\nRunning Parent()")
Parent()
Parent("a string", "something else", akeyword="a kwarg")

print("\nRunning Child1(), keep Parent.__init__(), overload surrogate Parent._init()")
Child1()
Child1("a string", "something else", akeyword="a kwarg")

print("\nRunning Child2(), overload Parent.__init__()")
#Child2() # __init__() requires arguments
Child2("a string", "something else", akeyword="a kwarg")

print("\nRunning Child3(), empty class, inherits everything")
Child3().some_base_method()

Output:

Running Parent()
Parent class _init;  <__main__.Parent object at 0x7f84a721fdc0> () {}
Parent class _init;  <__main__.Parent object at 0x7f84a721fdc0> ('a string', 'something else') {'akeyword': 'a kwarg'}

Running Child1(), keep Parent.__init__(), overload surrogate Parent._init()
Child1 class _init() overload;  <__main__.Child1 object at 0x7f84a721fdc0> () {}
Child1 class _init() overload;  <__main__.Child1 object at 0x7f84a721fdc0> ('a string', 'something else') {'akeyword': 'a kwarg'}

Running Child2(), overload Parent.__init__()
Child2 class __init__() overload;  <__main__.Child2 object at 0x7f84a721fdc0>
some base method in Parent
{}

Running Child3(), empty class, inherits everything, access things set by other children
Parent class _init;  <__main__.Child3 object at 0x7f84a721fdc0> () {}
some base method in Parent

As one can see, the overloaded definition(s) take the place of those declared in Parent class but can still be called BY the Parent class thereby allowing one to emulate the classical implicit inheritance initialization behavior Parent and Child classes both initialize without needing to explicitly invoke the Parent's init() from the Child class.

Personally, I call the surrogate _init() method main() because it makes sense to me when switching between C++ and Python for example since it is a function that will be automatically run for any subclass of Parent (the last declared definition of main(), that is).

ChrisN
  • 401
  • 4
  • 7