__init__ vs __new__ and When to Use Them
Tags: python
Published: 2022-03-06 13:18:08

## Introduction

I recently got asked to me what did `__init__` dunder method did in Python. And I was like, "it is used to initialize variables inside a class". And just after that, the follow-up question was, "then what is `__new__` used for. And I was completely blank and was not able to answer that.


I was not able to answer that question because there are not many tutorials out there that talk about `__new__`. I didn't want to happen this with you. And that is why I came up with this blog post for you.

## Similarities

Let's start with similarities.

* Both of them are called/invoked during the creation of the instance.

## Differences

Let's start with differences.

|   | __new__                                         | __init__                             |
|---|-------------------------------------------------|--------------------------------------|
| 1 | Called before __init__                          | Called after __new__                 |
| 2 | Accepts a type as the first argument                | Accepts an instance as the first argument|
| 3 | Is supposed to return an instance of the type received  | Is not supposed to return anything    |
| 4 | Used to control instance creation               | Used to initialize instance variables|

Talking about the first point. `__new__` is called when the instance is first created. This happens before the initialization of the class. 

By the way, did you note that the first argument to `__init__` is always `self`? This self is the instance of the class. `self` is what `__new__` returns.

Coming to the third point, `__new__` is supposed to return an instance of the class. Note that if `__new__` does not returns anything, `__init__` is not called.

## Which one of them is a constructor?

If you are coming from another language, you might be surprised that there are two similar things doing the same kind of work. Most languages you might have worked with would have something called a constructor. 

In Python, that concept is broken down into **constructor** and **initializer**. And you might have guessed, `__new__` is the constructor and `__init__` is the initializer.

Please note that `__new__` is implicit. Meaning that if you don't actually need to modify the creation of an instance of the class, you don't need to have a `new` method.

One more thing I'd like to add is... instance variables are local to an instance. So anything you are doing in init is local to that instance only. But anything you are doing in new will be affecting anything created for that type.

## Execution flow with an example

I am going to add some code to make this more engaging. Consider this example:

```python
class Demo:
    def __new__(cls, *args):
        print("__new__ called")
        return object.__new__(cls)

    def __init__(self):
        print("__init__ called")

d = Demo()
```

This is the simplest example of both `__new__` and `__init__` in action. If you save the above code in a file and run it, you'd see something like this:

```
$ python3 in_it.py 
__new__ called
__init__ called
```

As you can see, the new method is called first and then execution is passed to the init method.

## Use Cases

### Use case for `__new__`

One of the best use cases I can take an example of is when creating a Singleton. As we know, Singleton ensures a class only has one instance and provides a global point of access to it.

Some of the places I have seen singleton in action are in game programming where there is only one instance of the player. Another place, if you have used frontend libraries like Vuex (or Redux), there is only one global instance of the store. Doesn't matter how many instances you create, you'll end up having only one.

Let's see how to achieve similar behavior in Python:

```python
class Singleton:
    __instance = None
    
    def __new__(cls):
        if cls.__instance is None:
            print("creating...")
            cls.__instance = object.__new__(cls)
        return cls.__instance

s1 = Singleton()
s2 = Singleton()

print(s1)
print(s2)
```

Output:

```
$ python3 singleton.py 
creating...
<__main__.Singleton object at 0x7f943301d350>
<__main__.Singleton object at 0x7f943301d350>
```

As you can see, **creating...** is printed only once. they both point to the same memory location. In my case, it's `0x7f943301d350`.

You might be guessing that can't we do the same thing with `__init__`? No! That's because `__init__` does not return anything. We'll see in the next section what `__init__` is well suited for.

But first, I wanted to show you another use case of new.

```python
class Animal:
    def __new__(cls, legs):
        if legs == 2:
            return Biped()
        else:
            return Quadruped()

class Biped:
    def __init__(self):
        print("Initializing 2-legged animal")

class Quadruped:
    def __init__(self):
        print("Initializing 4-legged animal")

anim1 = Animal(legs=4)
anim1 = Animal(legs=2)
```

Output:

```
$ python3 newexample.py 
Initializing 4-legged animal
Initializing 2-legged animal
```

I am by no means a zoologist. But you get my point here. You can use `__new__` to conditionally create an instance from a class.

### Use case for `__init__`

As we have already seen previously. `init` is there to initialize an instance variable. These instance variables can later be used in different methods of the instance. 

I have extensively used `__init__` when I used to work with [Qt framework][1]. Qt is a framework for desktop-based UI development. When initializing UI objects, you can set how wide or long the window could be. You can also read preferences from a file and apply that during the initialization phase of an application. Setting the window title could be another example.

Here I'll demonstrate one such example:

```python
class Window(QWidget):
   def __init__(self, parent = None):
      super(Window, self).__init__(parent)
      self.resize(200, 100)
      self.setWindowTitle("My App")
```

The above example is by no means a complete example, but when set up correctly, it will show a window similar to this. 

<img src="https://d2kbulfv42d43j.cloudfront.net/2022/Q1/example_python_qt_application.png" alt="Sample PySide window">


## Key Takeaways

* In most cases, you don't need 
* `__new__` is called before `__init__`.
* `__new__` returns a instance of class. 
* `__init__` receives the instances of the class returned by `__new__`.
* Use `__init__` to initilize value.

The same concept can be used to answer the question of abstraction vs encapsulation.

## Conclusion

That is all I know about `__init__` vs `__new__`. If you have something in your mind that I missed. Please let me know.

I'll also list some references I look to write this blog post so that you can really the real source of information.

* <https://dev.to/pila/constructors-in-python-init-vs-new-2f9j>
* <https://www.reddit.com/r/learnpython/comments/2s3pms/what_is_the_difference_between_init_and_new/>
* <https://www.pythonprogramming.in/how-to-use-new-and-init-in-python.html>

[1]: https://www.qt.io/