Python
Object-Oriented Programming
__init__
__new__
Method Order

Why is __init__ always called after __new__?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python, __new__ and __init__ are the two steps of object creation. __new__ allocates memory and returns a new instance, then __init__ initializes that instance with attributes. __init__ is always called after __new__ because Python's type machinery calls them in sequence: first create the object, then initialize it. Understanding this distinction matters when implementing singletons, immutable types, caching, and metaclasses.

The Two-Step Process

When you write MyClass(args), Python executes:

python
1# What Python does internally:
2obj = MyClass.__new__(MyClass, args)  # Step 1: Create instance
3if isinstance(obj, MyClass):
4    obj.__init__(args)                 # Step 2: Initialize instance

__new__ is responsible for creating and returning the instance. __init__ is responsible for setting up the instance's attributes. Python only calls __init__ if __new__ returns an instance of the class.

new — The Constructor

python
1class MyClass:
2    def __new__(cls, *args, **kwargs):
3        print(f"__new__ called with cls={cls.__name__}")
4        instance = super().__new__(cls)  # Allocate memory
5        return instance
6
7    def __init__(self, value):
8        print(f"__init__ called with value={value}")
9        self.value = value
10
11obj = MyClass(42)
12# Output:
13# __new__ called with cls=MyClass
14# __init__ called with value=42

__new__ is a static method (it takes cls, the class itself, not an instance). It must return an instance — usually by calling super().__new__(cls).

init — The Initializer

python
1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6p = Person("Alice", 30)
7print(p.name)  # "Alice"
8print(p.age)   # 30

__init__ receives the already-created instance as self and sets up its attributes. It must return None — if it returns anything else, Python raises TypeError.

Why new Exists: Immutable Types

Immutable types like int, str, tuple, and frozenset cannot be modified after creation. Since __init__ runs after the object exists, it is too late to change an immutable object. __new__ lets you customize the object during creation:

python
1class PositiveInt(int):
2    def __new__(cls, value):
3        if value < 0:
4            value = abs(value)
5        return super().__new__(cls, value)
6
7    # __init__ cannot modify an int — it's immutable
8    # def __init__(self, value):
9    #     self = abs(value)  # This does NOT work
10
11print(PositiveInt(-5))   # 5
12print(PositiveInt(3))    # 3
13print(type(PositiveInt(3)))  # <class 'PositiveInt'>

Singleton Pattern with new

python
1class Singleton:
2    _instance = None
3
4    def __new__(cls, *args, **kwargs):
5        if cls._instance is None:
6            cls._instance = super().__new__(cls)
7        return cls._instance
8
9    def __init__(self, value=None):
10        # __init__ is called every time Singleton() is called
11        if value is not None:
12            self.value = value
13
14a = Singleton(10)
15b = Singleton(20)
16
17print(a is b)      # True — same instance
18print(a.value)     # 20 — __init__ ran again and overwrote value

Note that __init__ runs every time you call Singleton(), even if __new__ returns an existing instance. To prevent re-initialization, add a guard:

python
1class Singleton:
2    _instance = None
3    _initialized = False
4
5    def __new__(cls, *args, **kwargs):
6        if cls._instance is None:
7            cls._instance = super().__new__(cls)
8        return cls._instance
9
10    def __init__(self, value=None):
11        if not self._initialized:
12            self.value = value
13            self._initialized = True
14
15a = Singleton(10)
16b = Singleton(20)
17print(a.value)  # 10 — not overwritten

new Returning a Different Type

If __new__ returns an instance of a different class, __init__ is NOT called:

python
1class MyClass:
2    def __new__(cls):
3        print("__new__ called")
4        return 42  # Returning an int, not a MyClass instance
5
6    def __init__(self):
7        print("__init__ called")  # Never called!
8
9obj = MyClass()
10print(obj)        # 42
11print(type(obj))  # <class 'int'>
12# Only "__new__ called" is printed — __init__ is skipped

Python checks: is the return value of __new__ an instance of cls? If not, __init__ is skipped.

Object Caching with new

python
1class CachedString(str):
2    _cache = {}
3
4    def __new__(cls, value):
5        if value in cls._cache:
6            return cls._cache[value]
7        instance = super().__new__(cls, value)
8        cls._cache[value] = instance
9        return instance
10
11a = CachedString("hello")
12b = CachedString("hello")
13c = CachedString("world")
14
15print(a is b)  # True — same cached instance
16print(a is c)  # False — different string

The Full Object Creation Chain

python
1class Meta(type):
2    def __call__(cls, *args, **kwargs):
3        print(f"1. Meta.__call__ for {cls.__name__}")
4        instance = cls.__new__(cls, *args, **kwargs)
5        print(f"2. {cls.__name__}.__new__ returned {type(instance).__name__}")
6        if isinstance(instance, cls):
7            instance.__init__(*args, **kwargs)
8            print(f"3. {cls.__name__}.__init__ completed")
9        return instance
10
11class MyClass(metaclass=Meta):
12    def __new__(cls, value):
13        return super().__new__(cls)
14
15    def __init__(self, value):
16        self.value = value
17
18obj = MyClass(42)
19# 1. Meta.__call__ for MyClass
20# 2. MyClass.__new__ returned MyClass
21# 3. MyClass.__init__ completed

The metaclass __call__ method orchestrates the __new____init__ sequence.

Common Pitfalls

  • Forgetting to call super().__new__(cls): If __new__ does not call super().__new__(cls), no instance is created and you get None or an error. Always delegate to the parent class's __new__.
  • Returning a non-instance from __new__ accidentally: If __new__ returns the wrong type, __init__ is silently skipped. This is rarely intended and causes confusing bugs.
  • Re-initialization in Singleton pattern: __init__ runs every time the class is called, even when __new__ returns a cached instance. Add an _initialized flag to prevent overwriting attributes.
  • Trying to modify immutable types in __init__: You cannot change the value of int, str, or tuple in __init__ because the object is already created. Override __new__ to customize immutable types.
  • Using __new__ when __init__ suffices: Most classes should only implement __init__. Use __new__ only for immutable types, singletons, caching, or metaclass customization. Unnecessary __new__ overrides add complexity.

Summary

  • __new__ creates and returns a new instance; __init__ initializes it with attributes
  • Python calls __new__ first, then __init__ only if __new__ returned an instance of the class
  • Override __new__ for immutable types (int, str, tuple), singletons, and object caching
  • Override __init__ for setting up mutable instance attributes (the common case)
  • In the Singleton pattern, guard __init__ with a flag to prevent re-initialization

Course illustration
Course illustration

All Rights Reserved.