I’ve been learning more about Python recently, and as I was going through the excellent Dive into Python the author noted here that the __init__ method is not technically a constructor, even though it generally functions like one.
I have two questions:
-
What are the differences between how
C++ constructs an object and how
Python “constructs” an object? -
What
makes a constructor a constructor,
and how does the__init__method
fail to meet this criteria?
The distinction that the author draws is that, as far as the Python language is concerned, you have a valid object of the specified type before you even enter
__init__. Therefore it’s not a “constructor”, since in C++ and theoretically, a constructor turns an invalid, pre-constructed object into a “proper” completed object of the type.Basically
__new__in Python is defined to return “the new object instance”, whereas C++ new operators just return some memory, which is not yet an instance of any class.However,
__init__in Python is probably where you first establish some important class invariants (what attributes it has, just for starters). So as far as the users of your class are concerned, it might as well be a constructor. It’s just that the Python runtime doesn’t care about any of those invariants. If you like, it has very low standards for what constitutes a constructed object.I think the author makes a fair point, and it’s certainly an interesting remark on the way that Python creates objects. It’s quite a fine distinction, though and I doubt that calling
__init__a constructor will ever result in broken code.Also, I note that the Python documentation refers to
__init__as a constructor (http://docs.python.org/release/2.5.2/ref/customization.html)… so if there are any practical problems with thinking of
__init__as a constructor, then Python is in trouble!The way that Python and C++ construct objects have some similarities. Both call a function with a relatively simple responsibility (
__new__for an object instance vs some version ofoperator newfor raw memory), then both call a function which has the opportunity to do more work to initialize the object into a useful state (__init__vs a constructor).Practical differences include:
in C++, no-arg constructors for base classes are called automatically in the appropriate order if necessary, whereas for
__init__in Python, you have to explicitly init your base in your own__init__. Even in C++, you have to specify the base class constructor if it has arguments.in C++, you have a whole mechanism for what happens when a constructor throws an exception, in terms of calling destructors for sub-objects that have already been constructed. In Python I think the runtime (at most) calls
__del__.Then there’s also the difference that
__new__doesn’t just allocate memory, it has to return an actual object instance. Then again, raw memory isn’t really a concept that applies to Python code.