No, __init__ is not the python constructor

Eliecer Daza
3 min readApr 3, 2021
keyboard
Keyboard photo by author.

One of the questions we like to ask when we are interviewing a python dev, middle level (3+ years experience ) or up, is about some python core knowledge, it is: What is the constructor of a class in python?

Most of them, even the most advanced, said __init__, but they are wrong.

TLDR:

__init__ is the initializer, some kind of first place to fill the object attributes, but when __init__ is called; the instance was already created.
__new__ is the *real* constructor, it is here where the instance is created.

We made this question to know what kind of problems the dev faced, among other things.

In some cases, developers need to use __new__ in order to be able to manipulate if we want to create a new instance or not, you can think on a case you will need to create a singleton class (btw this is not the only way to do it but is one using __new__ new and __init__).

I’ll paste here what the official python doc say:

object.__new__(cls[, ...])Called to create a new instance of class cls. __new__() is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of __new__() should be the new object instance (usually an instance of cls).Typical implementations create a new instance of the class by invoking the superclass’s __new__() method using super().__new__(cls[, ...]) with appropriate arguments and then modifying the newly-created instance as necessary before returning it.If __new__() is invoked during object construction and it returns an instance or subclass of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to the object constructor.If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.object.__init__(self[, ...])Called after the instance has been created (by __new__()), but before it is returned to the caller. The arguments are those passed to the class constructor expression. 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; for example: super().__init__([args...]).Because __new__() and __init__() work together in constructing objects (__new__() to create it, and __init__() to customize it), no non-None value may be returned by __init__(); doing so will cause a TypeError to be raised at runtime.

And I left here the singleton example as well:

class OnlyOne(object):
class __OnlyOne:
def __init__(self):
self.val = None
def __str__(self):
return `self` + self.val
instance = None
def __new__(cls): # __new__ always a classmethod
if not OnlyOne.instance:
OnlyOne.instance = OnlyOne.__OnlyOne()
return OnlyOne.instance
def __getattr__(self, name):
return getattr(self.instance, name)
def __setattr__(self, name):
return setattr(self.instance, name)

More info about this pattern, here https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html

One of my lemas I want to share with you is:

RODF: Read the Official Documentation First

--

--