Back to Blog
Python

Python __init__ vs __new__: What Actually Runs

Python object creation runs __new__ before __init__. __new__ creates and returns the instance; __init__ initializes it. See practical examples, edge cases, and when to override __new__.

__new____init__object lifecyclePython internalssingleton pattern
Editorial illustration contrasting Python's __new__ method that creates an instance with __init__ that initializes its state.

Python object creation runs two methods in a fixed order: __new__ then __init__. __new__ is responsible for creating and returning a new instance. __init__ receives that instance and initializes its state. The distinction matters because __new__ determines whether an instance exists at all, while __init__ only runs on an instance that __new__ produced.

Although __new__ and __init__ both appear to construct an object, __new__ is the constructor and __init__ is the initializer. Knowing which one runs and when is the key to using either one correctly.

How Python Creates an Object

When you call Example(...), Python does not directly invoke __init__. It calls type.__call__, which invokes __new__ first, then conditionally invokes __init__.

class Example: def __new__(cls, *args, **kwargs): print("__new__ called") instance = super().__new__(cls) return instance def __init__(self, value): print("__init__ called") self.value = value obj = Example(42)

The output is:

__new__ called
__init__ called

super().__new__(cls) delegates to object.__new__, which allocates a bare instance of cls. Only after that allocation succeeds does Python pass the instance to __init__, along with the same arguments that were passed to the constructor call. This two-step sequence is the same for every class, whether or not you override either method.

What __new__ Returns and Why It Matters

The return value of __new__ controls whether __init__ runs at all. If __new__ returns an instance of the class itself, Python calls __init__ on that instance. If __new__ returns an instance of an unrelated class, or returns None, __init__ is skipped entirely.

class Other: pass class Weird: def __new__(cls, *args, **kwargs): return Other()

Calling Weird() returns an Other instance, and Weird.__init__ never runs. This is why a __new__ override must return the instance explicitly. If you forget the return statement, the method returns None, __init__ does not run, and your code receives a None value instead of an object.

When You Need to Override __new__

Most classes never need __new__, but some situations require it.

Immutable types are the most common case. You cannot set attributes on an instance of tuple, int, str, or frozenset inside __init__ because those types do not allow attribute assignment. The only way to customize their construction is through __new__.

class UpperString(str): def __new__(cls, value): return super().__new__(cls, value.upper())

Singleton patterns also rely on __new__ because the method can return an existing instance instead of allocating a new one.

class Singleton: _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance

Every call to Singleton() returns the same object. Note that __init__ still runs on that shared instance each time, so you need to guard against re-initialization if repeated calls would reset state you want to preserve.

Why Most Classes Only Need __init__

For ordinary classes, __new__ adds complexity without benefit. The default object.__new__ already allocates a fresh instance, and __init__ is the natural place to set attributes, validate arguments, and establish invariants.

class Account: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance

This is the common case. Reaching for __new__ here forces you to manually allocate the instance and return it, which is more code and more opportunity for error. The default behavior already does exactly what you need.

Common Mistakes and Edge Cases

A frequent mistake is forgetting to return the instance from __new__. Without an explicit return, the method returns None, and Python skips __init__ entirely. You end up with a None value instead of a usable object, and the failure often appears later when you try to access an attribute.

Another mistake is using __new__ and __init__ signatures that do not accept the same arguments. Python passes the constructor arguments to both methods, so a __new__ that requires one set of parameters and an __init__ that requires another can raise a confusing TypeError.

class Broken: def __new__(cls, value): return super().__new__(cls) def __init__(self, value, extra): self.value = value

Calling Broken(1) creates the bare instance, but __init__ then fails because it also expects extra.

A subtle edge case: if __new__ returns an instance of a subclass, the __init__ of that subclass runs, not the __init__ of the class where __new__ was defined. The method that runs is determined by the type of the returned instance, not by the class that defined __new__.

Runtime Cost and Instance Reuse

Because __new__ runs on every constructor call, any work placed there is paid on every instantiation. Allocation via object.__new__ is the normal cost of creating an object. If you override __new__ to perform expensive setup, that cost applies to each call, which can matter in hot paths.

The more interesting runtime behavior is instance reuse. A __new__ override can return a cached instance, which avoids allocation entirely. This is how singletons and some flyweight patterns work. The tradeoff is that __init__ still runs on the reused instance, so repeated calls can reset state that you intended to keep.

There is no general performance rule here. The decision depends on whether you are allocating fresh objects or reusing existing ones, and on how much work __init__ performs. Measure the actual allocation and initialization cost before optimizing.

Choosing Between __new__ and __init__

Use __init__ when you are setting up state on a freshly allocated instance, which covers nearly all normal classes.

Use __new__ when:

  • You are subclassing an immutable built-in such as tuple, str, or int.
  • You need to return a cached, reused, or shared instance.
  • You need to control the class of the returned object at creation time.
  • You are implementing a metaclass that must control class creation.

If none of those conditions apply, __init__ is the correct choice. Overriding __new__ without a concrete need adds a return-value requirement and a second code path that future maintainers must reason about. Keep the default object.__new__ and put your logic in __init__.

Python __init__ vs __new__: What Actually Runs and When to Use Each | RYUSLOG DEV