Definition of __new__ in Python
The __new__ method is a special method (or dunder method) in Python that intervenes before the __init__ method during object creation. While __init__ is responsible for initializing an already created instance, __new__ is responsible for the actual creation of that instance in memory. It is therefore the very first step in the lifecycle of a Python object.
Concretely, when you write MyObject(), Python first calls MyObject.__new__(MyObject) to create the instance, then MyObject.__init__(instance) to initialize it. Most of the time, you don't need to override __new__, because the default behavior inherited from the class object is sufficient. However, this method becomes essential in certain advanced cases that we will explore in detail.
If you want to dive deeper into this topic and master all of object-oriented programming in Python, we recommend following our complete Python course which covers these types of advanced concepts.
Understanding the role of __new__ in object creation
To properly understand __new__, it is essential to distinguish the two phases of object instantiation in Python:
| Step | Method | Role | Method type |
|---|---|---|---|
| 1. Creation | __new__ | Creates and returns a new instance | Implicit static method |
| 2. Initialization | __init__ | Configures the already created instance | Instance method |
The __new__ method receives the class as its first argument (conventionally named cls), unlike __init__ which receives the instance (named self). This makes sense: at the time __new__ is called, the instance doesn't exist yet.
__new__ is technically a static method that is treated specially by Python. It must imperatively return an instance, otherwise __init__ will never be called.
Signature of __new__
Here is the typical signature of __new__:
class MyClass:
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls)
return instance
def __init__(self, *args, **kwargs):
# Instance initialization
passYou will notice that __new__ calls super().__new__(cls) to delegate the actual creation of the object to the parent class (usually object). This instruction is what allocates memory and creates the raw instance.
The complete instantiation flow
Here is an example that illustrates the order in which methods are called:
class Demonstration:
def __new__(cls, value):
print(f"1. __new__ is called with cls={cls.__name__}")
instance = super().__new__(cls)
print(f"2. Instance created: {instance}")
return instance
def __init__(self, value):
print(f"3. __init__ is called with self={self}")
self.value = value
print(f"4. Initialization complete, value={self.value}")
obj = Demonstration(42)
# Output:
# 1. __new__ is called with cls=Demonstration
# 2. Instance created: <__main__.Demonstration object at 0x...>
# 3. __init__ is called with self=<__main__.Demonstration object at 0x...>
# 4. Initialization complete, value=42This flow clearly shows that __new__ always precedes __init__ and that the instance returned by __new__ is exactly the one passed to __init__ as self.
Practical use cases for __new__
Although overriding __new__ is an advanced case, there are several situations where this method proves essential. Here are the main use cases.
1. The Singleton pattern
The Singleton is a design pattern that guarantees a class can only have one single instance. It is one of the most classic use cases for __new__:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, name=None):
if name is not None:
self.name = name
# Testing the Singleton
a = Singleton("First")
b = Singleton("Second")
print(a is b) # True: it's the same object
print(a.name) # "Second" (reinitialized by the second call)
print(id(a) == id(b)) # TrueWarning: even though __new__ returns the same instance, __init__ is called every time. This can cause unexpected reinitializations. To avoid this, you can add a flag to initialize only once.
Here is an improved version that avoids reinitialization:
class SafeSingleton:
_instance = None
_initialized = False
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, name=None):
if not SafeSingleton._initialized:
self.name = name
SafeSingleton._initialized = True
a = SafeSingleton("First")
b = SafeSingleton("Second")
print(a.name) # "First" (not reinitialized)
print(b.name) # "First"
2. Subclassing immutable types
Immutable types like int, str, tuple or frozenset cannot be modified after their creation. Since __init__ intervenes after creation, it is too late to change the value of an immutable object. You must therefore use __new__:
class PositiveInt(int):
"""An integer that is always positive (absolute value)."""
def __new__(cls, value):
# We transform the value BEFORE creating the object
return super().__new__(cls, abs(value))
print(PositiveInt(-42)) # 42
print(PositiveInt(15)) # 15
print(type(PositiveInt(-7))) # Here is another example with strings:
class UpperStr(str):
"""A string that is always uppercase."""
def __new__(cls, content):
return super().__new__(cls, content.upper())
text = UpperStr("hello world")
print(text) # "HELLO WORLD"
print(type(text)) # This mechanism is impossible with __init__ alone, because immutable objects are already "frozen" by the time __init__ is called. This is why __new__ is essential here.
3. Registry system and factory pattern
You can use __new__ to implement a registry system that automatically returns the correct subclass based on the arguments:
class Animal:
_registry = {}
def __init_subclass__(cls, animal_type=None, **kwargs):
super().__init_subclass__(**kwargs)
if animal_type:
Animal._registry[animal_type] = cls
def __new__(cls, animal_type, name):
if cls is Animal:
subclass = cls._registry.get(animal_type, cls)
return super().__new__(subclass)
return super().__new__(cls)
def __init__(self, animal_type, name):
self.name = name
def speak(self):
return "..."
class Cat(Animal, animal_type="cat"):
def speak(self):
return f"{self.name} says: Meow!"
class Dog(Animal, animal_type="dog"):
def speak(self):
return f"{self.name} says: Woof!"
# Usage
animal1 = Animal("cat", "Whiskers")
animal2 = Animal("dog", "Rex")
print(type(animal1)) #
print(animal1.speak()) # Whiskers says: Meow!
print(type(animal2)) #
print(animal2.speak()) # Rex says: Woof!This pattern is very powerful for creating extensible architectures where new subclasses can be added without modifying existing code.
4. Instance cache (Object Pool)
You can use __new__ to reuse existing instances instead of creating new ones, which is useful for optimizing memory:
class Color:
_cache = {}
def __new__(cls, name):
normalized_name = name.lower().strip()
if normalized_name in cls._cache:
return cls._cache[normalized_name]
instance = super().__new__(cls)
cls._cache[normalized_name] = instance
return instance
def __init__(self, name):
self.name = name.lower().strip()
red1 = Color("Red")
red2 = Color("red")
red3 = Color(" RED ")
print(red1 is red2) # True
print(red1 is red3) # True
print(len(Color._cache)) # 1
__new__ and metaclasses
The __new__ method also plays a crucial role in metaclasses. A metaclass is a class whose instances are themselves classes. The __new__ method of a metaclass therefore controls the creation of classes, not instances:
class MetaValidation(type):
"""Metaclass that checks that each class has a docstring."""
def __new__(mcs, name, bases, namespace):
if not namespace.get('__doc__'):
raise TypeError(
f"Class '{name}' must have a docstring."
)
return super().__new__(mcs, name, bases, namespace)
class MyService(metaclass=MetaValidation):
"""Main service of the application."""
def execute(self):
pass
# This would raise TypeError:
# class ServiceWithoutDoc(metaclass=MetaValidation):
# passIn this context, __new__ receives four arguments: the metaclass (mcs), the name of the class to create, its bases (parent classes) and its namespace (dict containing its attributes and methods). It is a powerful tool for validating or transforming classes during their definition.
Differences between __new__ and __init__
Let's summarize the fundamental differences between these two methods to avoid any confusion:
| Characteristic | __new__ | __init__ |
|---|---|---|
| First argument | cls (the class) | self (the instance) |
| Role | Create the instance | Initialize the instance |
| Return value | Must return the instance | Returns nothing (None) |
| Call order | Called first | Called second |
| Method type | Implicit static method | Instance method |
| Override frequency | Rarely | Very often |
| Main use | Immutable types, singletons, metaclasses | Object configuration |
Best practices with __new__
Here are the essential recommendations for using __new__ correctly in your Python projects:
- Only override
__new__when necessary: in the vast majority of cases,__init__is sufficient. Using__new__without reason adds unnecessary complexity. - Always call
super().__new__(cls): forgetting this call will prevent instance creation and cause errors that are difficult to diagnose. - Always return an instance: if
__new__does not return an instance of the class,__init__will not be called. - Pass arguments correctly: make sure that
*argsand**kwargsare properly propagated tosuper().__new__()when necessary. - Document your usage: when you override
__new__, add a docstring explaining why this override is necessary. - Think about inheritance compatibility: if your class will be subclassed, make sure your implementation of
__new__works correctly with child classes.
Avoid putting initialization logic in __new__. This method is intended for creating the instance, not for configuring it. Keep the separation of responsibilities between __new__ (creation) and __init__ (initialization).
Here is an example of what you should not do:
# ❌ Bad practice: initialization logic in __new__
class Bad:
def __new__(cls, name, age):
instance = super().__new__(cls)
instance.name = name # ❌ This should be in __init__
instance.age = age # ❌ This too
return instance
# ✅ Good practice: clear separation of responsibilities
class Good:
def __init__(self, name, age):
self.name = name
self.age = age
Special case: __new__ returning an object of a different type
An interesting and sometimes confusing behavior: if __new__ returns an object that is not an instance of the class, then __init__ will not be called:
class Surprise:
def __new__(cls):
print("__new__ called")
return "I am a string, not an instance of Surprise"
def __init__(self):
print("__init__ called")
obj = Surprise()
print(obj) # "I am a string, not an instance of Surprise"
print(type(obj)) #
# Note: __init__ is NEVER called hereThis behavior is used in certain advanced cases, but it can be a source of confusion. Keep it in mind when debugging instantiation-related issues.
Frequently asked questions
What is the difference between __new__ and __init__ in Python?
__new__ is responsible for creating the instance in memory and receives the class (cls) as its first argument. __init__ is responsible for initializing the already created instance and receives the instance (self) as its first argument. __new__ is called before __init__ and must return an instance, while __init__ returns nothing. In daily practice, you will only need to override __init__ in the vast majority of cases.
When should you use __new__ instead of __init__?
You should use __new__ in three main cases: when you are subclassing an immutable type (like int, str, tuple) and need to modify the value before the object is created; when you are implementing the Singleton pattern to guarantee a unique instance; and when you are working with metaclasses to control the creation of classes themselves. Outside of these cases, always prefer __init__.
Why is __init__ not called after __new__ in some cases?
If __new__ returns an object that is not an instance of the class (or one of its subclasses), Python does not call __init__. This is a safety mechanism: __init__ expects an object of the correct type as self. If you forget to return an instance (for example by forgetting the return statement), __new__ will implicitly return None, and __init__ will not be called either.
How can you learn to master __new__ and advanced OOP in Python?
Mastering __new__ and advanced object-oriented programming concepts in Python requires practice and structured learning. We recommend following our dedicated Python course on Believemy, which covers in depth special methods, metaclasses, design patterns and many other essential topics to become a proficient Python developer.