DEV Community

Discussion on: Python: __init__() is not the only constructor

Collapse
 
eranelbaz profile image
eranelbaz • Edited

So I still didn't understand, if __new__ is the actual constructor, why we see __init__ as a constructor in almost any Python code?

Collapse
 
nestedsoftware profile image
Nested Software • Edited

Technically the __new__ method takes a class and generates an instance of that class. __init__ is used to then initialize the properties of the instance that was created by __new__. So __new__ is the constructor: Its job is to build a new instance object using the class as a template. I think it is very rare to override __new__ because its default behaviour, which is to create an empty instance of the particular class, is usually what we want.

In everyday Python programming, we just override the __init__ method to assign values to the object that was already created earlier by the default __new__ behaviour. __init__ is not the constructor, since it receives a pre-created instance object as a parameter - usually we call this parameter self. Instead, it's an initializer - it initializes an instance object.

As an example, and there are probably more ways to do this, you could override __new__ to limit the number of instances of an object that can be created, or to obtain them from a pool, that sort of idea. So there are probably use-cases for overriding __new__ but I doubt that you'd need to worry about it for everyday usage.

Update: I looked into the nomenclature, and it does not seem to me that Python has the concept of "constructor" used in the documentation in the same way that it's used for languages like Java or C++. Instead the docs mention that the call used to create an object, like say Foo(), is a constructor expression:

docs.python.org/3/reference/datamo...

This constructor expression calls __new__ and then __init__ internally. I guess neither of the latter would officially be called a constructor. I think it's okay to call __init__ the constructor informally though, since it does pretty much the same kind of thing that constructors in languages like Java, C#, C++ do.

Collapse
 
canizalesdiaz profile image
Jorge Cañizales Díaz • Edited

__new__ is what Objective-C and C++ would call an allocator: Its responsibility is to decide what "chunk of memory" to use for a new object.

Calling super().__new__ is the default behavior of allocating new memory in the heap and using that.

But for performance-critical code, you could implement a memory pool (or "arena") by selecting objects out of a contiguous array.

Or, if your class should have value semantics, you can cache new objects by value and have __new__ return already-existing objects. This technique is useful in other contexts too: Java does it automatically for small numerical objects and small strings (which are immutable, so caching them this way improves runtime and memory). Another context you might want to do it is for an object that represents a remote resource: Having only one local object per remote instance simplifies its code considerably when it comes to locking and caching remote state.

Should you call __new__ a constructor and say __init__ isn't a constructor? It doesn't matter. Although I think it's confusing for people familiar with other languages to say __init__ isn't the constructor, and kinda moot if one doesn't offer a better description for it.