__new__ and __init__ in Python

Differences between __new__() and __init__() methods in Python.

1 __new__()

__new__() method in Python class is responsible for creating a new instance object of the class. __new__() is similar to the constructor method in other OOP (Object Oriented Programming) languages such as C++, Java and so on.

class Animal(object):
    def __new__(cls, *args, **kw):
        return super().__new__(cls)
    def eat(self):
        print('eat something!')

1.1 cls parameter

The first parameter cls represents the class being created.

Why the first parameter of __new__() method is the cls rather than the self? Because the instance object has not been created yet and actually does not exist while the __new__() is calling, using self inside __new__() makes no sense.

1.2 Typical implementation

In most cases, you needn't to implement __new__() yourself. Python implicitly provides a default and typical implementation of __new__() which will invoke the superclass’s __new__() method to create a new instance object and then return it. So following two definations of the Animal class are equivalent indeed.

class Animal(object):
    def __new__(cls, *args, **kw):
        return super().__new__(cls)
    def eat(self):
        print('eat something!')

class Animal(object):
    def eat(self):
        print('eat something!')

1.3 Return value

You don't have to return a value in __new__() method.

If the __new__() method of your class returns an instance of cls, then the new instance’s __init__()method will be invoked automatically and the same arguments *args and **kw will be passed to the __init__() method as well.

If the __new__() method of your class doesn't return an instance of cls, the __init__() method will not be called. So it allows you to take more control over how new instance objects are created and to return an instance object of an entirely different class if you like.

2 __init__()

The instance method __init__() is the initializer of a class. It is best to set initial values to attributes of an instance object in the __init__() method.

class Animal(object):
    def __init__(self, name):
        self.name = name

The __init__() method doesn't have to return a value. Of course it can if you like, but Python will just ignore the returned value.

Although you can also set initial values in the __new__() method, it's better to do initialization inside the __init__().

NOT recommended:

class Animal(object):
    def __new__(cls, name):
        print('__new__() called.')
        obj = super().__new__(cls)
        obj.name = name
        return obj
    
a = Animal('Bob')
print(a.name)

Recommended:

class Animal(object):
    # Can be omitted, Python will give a default implementation
    def __new__(cls, *args, **kw):
        print('__new__() called.')
        print('args: ', args, ', kw: ', kw)
        return super().__new__(cls)
    
    def __init__(self, name):
        print('__init__() called.')
        self.name = name
        
a = Animal('Bob')
print(a.name)

As mentioned above, the __init__() and the __new__() will receive the same arguments except the first argument ( cls or self). For example, the expression Animal('Bob') will invoke __new__() with argument 'Bob'. After the __new__() returning the created Animal object, Python will call __init__() automatically and pass the argument Bob to it.

Comments