__init__ as a constructor?
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)
Solution 1:
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.
Solution 2:
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".
Solution 3:
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.
Solution 4:
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 thecls
in above signature is for. Again, likeself
,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:
__new__()
is always called before__init__()
.- First argument is the class itself which is passed implicitly.
- 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.