63

Dive into Python -

It would be tempting but incorrect to call this the constructor of the class. It's tempting, because it looks like a constructor (by convention, __init__ is the first method defined for the class), acts like one (it's the first piece of code executed in a newly created instance of the class), and even sounds like one (“init” certainly suggests a constructor-ish nature). Incorrect, because the object has already been constructed by the time __init__ is called, and you already have a valid reference to the new instance of the class.

Quote suggests it is incorrect to call __init__ as a constructor because the object is already constructed by the time __init__ is called. But! I have always been under the impression that the constructor is called only after the object is constructed because it is essentially used to initialized the data members of the instance which wouldn't make sense if the object didn't exist by the time constructor was called? (coming from C++/Java background)

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
Vaibhav Bajpai
  • 16,374
  • 13
  • 54
  • 85
  • 1
    In C++ the object isn't complete either when the constructor is called; consider e.g. virtual function calls from a base class' constructor. – Georg Fritzsche Jul 05 '11 at 06:12
  • 14
    Drawing comparisons between C++ and Python object initialization is useless; they're utterly different and incomparable systems. I disagree with the quote: it's perfectly natural to call `__init__` the ctor. – Glenn Maynard Jul 05 '11 at 06:39
  • 2
    @Georg: If a Python base class calls a method that is overridden in a subclass, and that method used attributes that haven't yet been set up (because their initialization occurs after the call to the base class constructor in the subclass constructor), then you get errors, just as in C++. In C++ when a constructor is called the instance is already allocated in memory, but no values have been filled in. In Python, the instance dictionary already exists, but nothing has been inserted. Insofar as you can draw analogies between such different systems, these seem to be the same thing. – Ben Nov 02 '11 at 01:19
  • This is a matter of terminology, not technology. We are used to constructors in other languages being used with an existing reference doing the initialization, i.e. doing exactly `__init__`'s job. I also don't like calling this initialization function a constructor (whether in Python, C++ or elsewhere) but who am I to alter common terminology. I simply avoid the word constructor at my courses as much as possible but accept when others use the word. – Pavel Šimerda Jun 05 '18 at 14:46

6 Answers6

56

If you have a class Foo then:

  • Foo() is the constructor
  • Foo.__init__() is the initializer
  • Foo.__new__() is the allocator

Construction of a Python object is simply allocation of a new instance followed by initialization of said instance.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 13
    Whatever `__init__` is, I would disagree that `Foo()` is a constructor. `Foo()` is a call to the thing named Foo. If Foo is a class that behaves as is usual, this call will result in the construction of a new object, but that's the code that is *reached* by calling `Foo()`, not the expression `Foo()` itself. – Ben Jul 05 '11 at 07:41
  • @Ignacio what would you call `__del__`? (destructor?) – Vaibhav Bajpai Jul 06 '11 at 00:57
  • 35
    And actually, according to the language used in http://docs.python.org/reference/datamodel.html#basic-customization, `Foo()` is a **constructor expression**, and `Foo.__init__` is a **constructor**. (And from the same reference, `__del__` is "also called a destructor"; the term finalizer is not used). This urban myth that `__init__` must not be called a constructor is just plain wrong. – Ben Oct 31 '11 at 01:34
  • @Ben Great detective work. I was really confused by that assertion. I can't believe it made its way into Dive Into Python. – temporary_user_name Sep 20 '13 at 04:49
  • @Ben is this still true in Java 3? Following your link, I'm having a hard time seeing how the word "constructor" refers to `Foo.__init__` – Josiah Yoder Jul 03 '20 at 19:25
  • 2
    @JosiahYoder No, they changed the description at some point. It's still there in the Python 2.6 docs (https://docs.python.org/2.6/reference/datamodel.html#basic-customization), where the section on `__init__` methods says "As a special constraint on constructors, no value may be returned". – Ben Jul 04 '20 at 06:52
53

Personally, I find "__init__ is not a constructor" to be pretty fine hair-splitting.

__init__ is called when a new object is requested. It is supposed to use its arguments to assign attributes on the new object, such that the required invariants for normal operation of the object are set up. The object is already a valid pre-existing place to store attributes by the time the code in __init__ begins running. The new object normally has no attributes defined on it already when the code in __init__ begins running (other than the ones that all objects possess).

A C++ constructor is called when a new object is requested. It is supposed to use its arguments to assign to fields on the new object, such that the required invariants for normal operation of the object are set up. The object is already a valid pre-existing place to store fields by the time the code in the constructor begins running. The new object has all its declared fields already when the code in the constructor begins running, but they contain garbage.

A Java constructor is called when a new object is requested. It is supposed to use its arguments to assign to fields on the new object, such that the required invariants for normal operation of the object are set up. The object is already a valid pre-existing place to store fields by the time the code in the constructor begins running. The new object has all its declared fields already when the code in the constructor begins running, with their default values.

The major difference between an __init__ method and a C++/Java constructor is in that last sentence I've highlighted, and that's just the difference between the static nature of Java/C++ and the dynamic nature of Python. I don't think this warrants calling them fundamentally different concepts that must not be referred to by the same word.

I think the main reason Pythonistas don't like to refer to __init__ as a constructor is that people think of C++/Java constructors as "making a new object", because that's what they seem to do when you call them. But there's really two things going on when you call a constructor; a new object is created and then the constructor is called to initialise it. In C++/Java the "create a new object" part of that is invisible, whereas that can be exposed/customised in Python (via the __new__ method).

So while the role of the __init__ method is extremely similar to the role of a C++/Java constructor, some people prefer to emphasise the fact that this isn't the whole process by saying that "__init__ is not a constructor".

Ben
  • 68,572
  • 20
  • 126
  • 174
  • 4
    The difference you indicate is an argument to call `__init__` a constructor even more. After all, it does even more "construction" (creating the attributes, not only initializing them) than the constructors from C++/C#/Java. – BartoszKP Feb 07 '18 at 14:54
6

From http://www.programiz.com/article/python-self-why

__init__() is not a constructor

[..]One important conclusion [..] is that, __init__() is not a constructor. Many naive Python programmers get confused with it since __init__() gets called when we create an object. A closer inspection will reveal that the first parameter in __init__() is the object itself (object already exists). The function __init__() is called immediately after the object is created and is used to initialize it.

Technically speaking, constructor is a method which creates the object itself. In Python, this method is __new__(). A common signature of this method is

__new__(cls, *args, **kwargs)

Regarding the answert given by Ben, I would argue here, that most languages don't follow that defintion (completely).

Furthermore:

When __new__() is called, the class itself is passed as the first argument automatically. This is what the cls in above signature is for. Again, like self, cls is just a naming convention. Furthermore, *args and **kwargs are used to take arbitary number of arguments during method calls in Python.

Some important things to remember when implementing __new__() are:

  1. __new__() is always called before __init__().
  2. First argument is the class itself which is passed implicitly.
  3. Always return a valid object from __new__(). Not mandatory, but thats the whole point.

Bottomline (for me): __new__() appears to be the constructor, not __init__() although -by all practical means __init__() does part of what most people think a constructor will do.

Marc
  • 117
  • 1
  • 7
  • 2
    But when you write a Java/C#/C++/any-OO-language constructor, the code you write is invoked on an already existing object, just like `__init__` (and unlike `__new__`). The constructor method you write doesn't return the object, it modifies it in place by writing to its attributes and then just stops, just like `__init__` (and unlike `__new__`). `__new__` does **not** do what constructors do in those other languages, it does what the language system does for you **before** the constructor you write gets called. – Ben Feb 07 '18 at 21:23
  • 3
    I can understand the claim that "construction" should be the whole "allocate a new object and then initialize its attributes" process; everything that the call `SomeClass(1, 2, 3)` is doing, not just the invocation of `__init __`. But if you want to make that claim, you are **also** arguing that Java constructors should not be called constructors, since they do exactly what `__init__` does in that process. And that definition *still* doesn't end up with reasonable grounds to call `__new__` a constructor, since it is **also** only one part of that whole construction process. – Ben Feb 07 '18 at 21:34
6

Constructor returns an instance and can fail. But __init__ does not return an instance. Even when __init__ raises and exception, __del__ is called to delete the instance.

This can be seen here:

class A(object):
    def __init__(self):
        raise ValueError

    def __del__(self):
        print "Called"

def main():
    try:
        a = A()
    except ValueError, e:
        print "ValueError"

if __name__ == '__main__':
    main()

__new__ on the other hand, returns an instance.

Rumple Stiltskin
  • 9,597
  • 1
  • 20
  • 25
  • 1
    -1 Constructors in Java/C++ do not return an instance either, unlike `__new__`. And whether destructors/finalizers are called on an instance after an uncaught exception escapes the constructor is a highly specific technical detail, nothing to do with the basic concept referred to by the word "constructor"; nobody would stop calling Java constructors "constructors" if the JVM was patched to change that. – Ben Oct 31 '11 at 01:40
  • +1 Exceptions in constructor is a substantial part of its behavior. In C++ destructor of the currently constructed object isn't called at exception. So I would consider this answer not complete, but useful nevertheless. – Ilia Barahovsky Nov 10 '15 at 06:21
-1

In "Programming Python : Introduction to Computer Science" from John Zelle says, "The special method __init__ is the object constructor. Python calls this method to initialize a new object. The role of __init__ is to provide initial values for the instance variables of an object."

fkkcloud
  • 167
  • 4
  • 11
-6

__init__ is not a constructor, but for reasons that won't matter to you as you're learning Python. It behaves the way you're used to constructors behaving in C++ and Java.

krasnerocalypse
  • 966
  • 6
  • 6