Python __init__ vs __new__: What Actually Runs
python **init** vs **new**: Understand the difference between Python's __new__ and __init__: which creates the instance, which initializes it, and when overriding __ne...
python init vs new requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
In Python, __new__ and __init__ handle two different stages of object creation. __new__ is a static method that receives the class and is responsible for creating and returning a new instance. __init__ is an instance method that receives the already-created instance and initializes its state. The distinction matters because __new__ runs first and decides whether an instance exists at all, while __init__ only runs on an instance that __new__ produced.
The confusion around python **init** vs **new** usually comes from the fact that both methods appear to construct an object. In practice, __new__ is the constructor and __init__ is the initializer. Knowing which one runs and when is the key to using either 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 a different 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 mismatched signatures for __new__ and __init__. Both receive the same arguments from the constructor call, so inconsistent parameter lists cause confusing TypeError failures.
class Broken: def __new__(cls, *args, **kwargs): return super().__new__(cls) # no __init__ defined -> object created but never initialized
If you define __new__ with *args, **kwargs but __init__ with specific parameters, the call will fail when the argument counts do not line up.
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, orint. - 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 intercept instance 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__.