Python __new__ vs __init__: When to Use Each
python **new** vs **init**: Understand the difference between Python's __new__ and __init__ methods, when to override each, and how they control object creation.
Every Python object goes through two distinct creation steps: __new__ and __init__. The first allocates the instance, the second initializes it. Many developers treat them as interchangeable, but they serve different purposes and are called at different times. Understanding the difference between python **new** vs **init** is essential for writing custom classes, implementing singletons, or working with metaclasses.
The Object Creation Pipeline
When you call ClassName(), Python does not directly allocate memory and call __init__. Instead, it invokes the class's __call__ method, which is inherited from type. That method coordinates two separate hooks:
__new__is called first. It receives the class itself as the first argument and is responsible for creating and returning a new instance.__init__is called next, but only if__new__returned an instance of the class. It receives that instance asselfand initializes its state.
Here is a minimal example that shows the order:
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)
Running this prints:
__new__ called __init__ called
__new__ is a static method in practice, though it is not decorated. It receives the class as its first parameter, not an instance. __init__ receives the already-created instance. If __new__ returns an object of a different type, __init__ is never called. This behavior is the core of the distinction between the two methods.
When to Override __new__
Override __new__ when you need to control the creation of the instance itself, before any initialization happens. Common cases include:
- Immutable types: Because objects like
tupleorstrcannot be modified after creation, you must set their internal state during__new__. There is no chance to do it in__init__. - Singleton pattern: You want every call to the class to return the same instance.
- Caching: You want to reuse existing instances instead of allocating new ones.
- Metaclass-driven creation: When you need to customize how the class itself is built.
A classic singleton implementation using __new__ looks like this:
class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # True
Here __new__ checks whether an instance already exists. If it does, it returns that cached instance without allocating a new one. Note that __init__ will still be called on the returned instance every time you call Singleton(). If your singleton needs to preserve state, you must guard __init__ as well, or use a different pattern.
When to Override __init__
For the vast majority of classes, __init__ is the only method you need. It runs after the instance exists and is the natural place to set attributes, validate arguments, and prepare the object for use.
class Account: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance if balance < 0: raise ValueError("Balance cannot be negative")
__init__ can assume that self is a fully allocated instance. You do not need to call super().__init__() unless you are subclassing a class that defines its own __init__. The default object.__init__ does nothing, so calling it is optional but harmless.
If you only need to set attributes or perform validation, override __init__. Overriding __new__ in this situation adds complexity without benefit.
Common Mistakes and Pitfalls
One frequent mistake is forgetting to call super().__new__(cls) inside __new__. If you do not return an instance, Python will not call __init__, and your object creation will fail or produce None.
class Broken: def __new__(cls): # Missing super().__new__(cls) pass b = Broken() # TypeError: object.__new__() takes exactly one argument
Another issue is returning an object of a different type from __new__. When that happens, __init__ is skipped entirely, which can lead to surprising behavior:
class Weird: def __new__(cls): return 42 def __init__(self): print("This never runs") w = Weird() print(w) # 42
This is rarely what you want. Use it only when you deliberately want to bypass initialization, such as when returning a cached instance of a different class.
A third mistake is manually calling __init__ from __new__. This is redundant because Python already calls __init__ after __new__ returns an instance of the class. Doing it manually can cause double initialization.
Interaction with Metaclasses and Inheritance
Metaclasses also define __new__ and __init__, but they operate on classes, not instances. When you define a class, Python calls the metaclass's __new__ to create the class object, then the metaclass's __init__ to initialize it. This is separate from the instance-level __new__ and __init__.
class Meta(type): def __new__(mcs, name, bases, namespace): print(f"Meta.__new__ creating {name}") return super().__new__(mcs, name, bases, namespace) def __init__(cls, name, bases, namespace): print(f"Meta.__init__ initializing {name}") super().__init__(name, bases, namespace) class MyClass(metaclass=Meta): pass
When you instantiate MyClass, the instance-level __new__ and __init__ run, not the metaclass ones. The metaclass hooks run only once when the class is defined.
Inheritance adds another layer. If a subclass does not override __new__, it inherits the parent's implementation. If the parent's __new__ returns an instance of the parent class, that can break the subclass. Always call super().__new__(cls) with the actual cls argument so that the returned instance is of the correct type.
Practical Example: Immutable Point
A common use of __new__ is to create a subclass of an immutable built-in type. For example, a Point class that inherits from tuple must set its values during creation because tuples cannot be modified afterward.
class Point(tuple): def __new__(cls, x, y): return super().__new__(cls, (x, y)) @property def x(self): return self[0] @property def y(self): return self[1] p = Point(3, 4) print(p.x, p.y) # 3 4 print(p) # (3, 4)
Here __init__ is not defined because there is nothing to initialize after the tuple is created. The values are passed to tuple.__new__ and stored internally. This pattern is also used for custom string or frozenset subclasses.
Performance and Maintainability Considerations
Overriding __new__ adds a small amount of overhead because it is an extra method call before __init__. For most classes, this cost is negligible. The real concern is maintainability: __new__ logic runs before the object exists, which makes debugging harder if the logic is complex.
Use __new__ only when the creation process itself must be customized. For example, a singleton implemented with __new__ is simple but not thread-safe. If multiple threads call the constructor simultaneously, both may see _instance is None and create separate instances. A module-level singleton or a metaclass with a lock avoids this issue.
Another consideration is that __new__ is called for every instance, including when you use copy.copy or pickle. If your __new__ performs heavy work, it will affect those operations. Keep __new__ minimal and defer heavy setup to __init__ whenever possible.
When you need to control instance allocation, caching, or immutable types, __new__ is the correct tool. For ordinary attribute initialization, stick with __init__. Knowing which method to override keeps your code clear and avoids subtle bugs in object creation.