Python __new__() method explained with examples
Tags: python, programming, beginners
Published: 2023-05-08 17:24:43

> ✋ **Update:** This post was originally published on my blog [decodingweb.dev](https://www.decodingweb.dev), where you can read the [latest version](https://www.decodingweb.dev/python-new-magic-method) for a 💯 user experience. _~reza_

Python `__new__()` method is static method (a.k.a magic or dunder method) that gives the programmer more control over how a specific class (cls) is instantiated.

This quick guide explains the `__new__()` method and how and when to use it.


## How does the Python `__new__()` method work?

Python calls the `__new__()` method every time you instantiate a class. It does the instantiation in two steps:

**First:** it invokes the `__new__()` method of the class to create and return an instance (this instance is then passed to `__init__()` as its first argument `self`)

**Next:** the `__init__()` method is invoked to initialize the object state. Please note the `__init__()` method can’t return anything (except for `None`).


## When to use the Python `__new__()` method?

Well, most of the time, you don’t need to! 

Python does it all for you. However, you might want to override this dunder method if you need more control over the instantiation process.

Below are three [not-so-common] use cases of the `__new__()` magic method:

- <u>Subclassing built-in types</u>
- <u>Custom initialization logic</u>
- <u>Singleton classes</u>

**1. Subclassing built-in types:** We create a subclass to create a new class based on a base class, which overrides some of its parent’s data/behavior.

In Python, you can subclass immutable built-in types (e.g., `int`, `float`, and `str`) to add custom behavior to a built-in data type.

For instance, the `bool` type is a subclass of the immutable `int`.  In fact, `True` and `False` are integer numbers `1` (for True) and `0` (for False).

Since the base class is `int`, we can even do mathematical operations on boolean values. 

```
>>> a = True
>>> b = False
>>> a + b
1
>>> a = True
>>> b = True
>>> a + b
2
>>> bool.__bases__
(,)
```

We can also create our own subclass of int (or any other data type) thanks to the `__new__()` method.

Imagine you need a data type that stores integers as positive numbers regardless of the given value (1, 3, -45, -50). At the same time, you want to have access to all the functionalities the built-in int type offers:

```python
class PositiveInt (int):
    def __new__(cls, value):
        return int.__new__(cls, abs(value))
```

In the above example, our subclass `PositiveInt` extends the standard `int` class, but it implements its own `__new__()` method to transform the given value into a positive number.

Inside the `__new__()` method, we call the `__new__()` of the parent (`int`) and pass it the absolute value (`abs(value)`) of the given number.

Let's try it out:

```python
b = PositiveInt(-34)
print(b)
# output: 34

c = PositiveInt(784)
print(c)
# output: 784

print(b + c)
# output: 818
```

Done!

**2. Custom initialization logic:** You can use the `__new__()` method to create customized instantiation logic.

Imagine, you need to limit the number of instances created for a specific class:

```python
class Players(object):
    currentInstances = 0
    maxInstances = 4

   def __new__(cls, value):
        if cls.currentInstances >= cls.maxInstances:
            raise ValueError(f'You can only make {maxInstances} instances.')

        cls.currentInstances += 1
        return super().__new__(cls)

    def __init__(self, value):
        self.value = value
```

In the above class `Player`, we have a variable named `currentInstances` to store the current number of instances created.

In the `__new__()` method, we ensure `currentInstances` never exceeds `maxInstances`. If it does so, we throw an exception. And if not, we instantiate the class by calling the parent object `__new__()` method and return the result.

Finally, we increment `currentInstances` by `1`.

If we try to instantiate the `Player` class 5 times, we'll get an exception on the fifth try.

```
ValueError: You can only make 4 instances
```

**3. Creating singleton classes:** Another [controversial] use case for the `__new__()` method is to create Python singleton objects. 

Singleton classes should have only one instance. 

Technically, you can use the `__new__()` method to ensure only one instance of a specific class is created and returns the existing instance to all subsequent constructor calls.

Here's how we'd do it by using the `__new__()` method:

```python
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
```

In the above example, we define a class named Singleton with the attribute `_instance`, initially set to `None`. 

When you instantiate the class, the `__new__()` method is invoked, checking whether the `_instance` attribute is `None`. 

If it is, it creates a new instance using the `super().__new__(cls)` and assigns it to the `_instance` attribute. If the _instance attribute already refers to an existing object, it returns it.

This ensures that only one instance of our class can exist at any given time.

While this works fine, it isn't the most Pythonic way of reusing objects. In fact, it's almost useless in Python!

A more Pythonic approach would be to use The **Global Object Pattern**. In Python, when you only need a single instance of a class, you probably don't need a class definition at all. You can place your data/functionality at a module level instead; Modules have their own namespaces and are singleton by design.

On the other hand, every time you refer to a module, Python returns the same module object. This is why we make singleton classes. Something that Python provides out of the box.

**Sometimes it's acceptable, though!** The one situation using the Singleton pattern sounds reasonable is when you're working with legacy code. 

Let's say, due to new requirements, you need to use a specific class as a single object across the code base. However, it’s not an option to update all the legacy code to use the global object approach.

In that case, making the class singleton might be helpful to implement the requirement while keeping the old syntax.

I haven't personally encountered any of the above use cases, but you might!

## Wrapping up

In conclusion, the `__new__()` magic method provides lots of flexibility for controlling how a class is instantiated.

With the help of the `__new__()` method, you can subclass built-on types, create singleton objects, and create classes with customized instantiation/ initialization logic. 

I hope you found this quick guide helpful. Thanks for reading!