last modified March 25, 2025
This comprehensive guide explores Python's __new__ method, the
special method responsible for object creation before __init__ is
called. We'll cover its purpose, use cases, and advanced patterns through
detailed examples.
The __new__ method is a static method that creates and returns a
new instance of a class. It's called before __init__ and is
responsible for the actual object creation, while __init__ handles
initialization.
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(10)
In this basic example, we see the order of operations when creating an
object. The __new__ method:
super().__new__(cls)__init__
Key characteristics of __new__:
__init__)
The __new__ method allows complete control over instance
creation. This example shows how to customize what gets created.
class CustomObject: def __new__(cls, value): if value < 0: return None # Return None for negative values instance = super().__new__(cls) instance.created_at = time.time() return instance def __init__(self, value): self.value = value obj1 = CustomObject(5) # Creates instance obj2 = CustomObject(-1) # Returns None
This example demonstrates several important concepts:
__init__ is called__init__ method only runs if __new__ returns an instance of the classPractical applications include:
The __new__ method is perfect for implementing the Singleton
pattern, which ensures a class has only one instance.
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.initialized = False
return cls._instance
def __init__(self):
if not self.initialized:
print("Initializing Singleton")
self.initialized = True
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True
This implementation guarantees only one instance exists by:
_instanceinitialized flag to prevent __init__ from
running multiple timesImportant considerations:
initialized flag prevents re-initialization
__new__ can be used to create immutable objects by controlling
attribute assignment.
class ImmutablePoint:
__slots__ = ('x', 'y') # Prevents dynamic attribute creation
def __new__(cls, x, y):
instance = super().__new__(cls)
instance.x = x # Allowed during creation
instance.y = y
return instance
def __setattr__(self, name, value):
raise AttributeError(f"Cannot modify {name}")
p = ImmutablePoint(3, 4)
print(p.x, p.y) # Works
p.x = 5 # Raises AttributeError
This immutable implementation combines several techniques:
__slots__ prevents adding new attributes__new__ sets initial values during creation__setattr__ blocks subsequent modificationsWhy this works:
__new__ before __setattr__ takes effect__slots__ makes the object more memory efficient
__new__ is essential when subclassing immutable built-in types
like tuple or str.
class NamedTuple(tuple): def __new__(cls, items, name): instance = super().__new__(cls, items) instance.name = name return instance def __init__(self, items, name): # __init__ is still called but often unused in these cases pass nt = NamedTuple([1, 2, 3], "My Numbers") print(nt) # (1, 2, 3) print(nt.name) # "My Numbers"
When subclassing immutable types:
__new__ must do all the work since the object is immutable after creation__new____new__ before the object becomes immutableCommon use cases:
__new__ can implement object pooling to reuse instances instead of
creating new ones.
class DatabaseConnection:
_pool = {}
_max_pool_size = 3
def __new__(cls, connection_string):
if connection_string not in cls._pool:
if len(cls._pool)>= cls._max_pool_size:
raise RuntimeError("Connection pool exhausted")
instance = super().__new__(cls)
instance._connect(connection_string)
cls._pool[connection_string] = instance
return cls._pool[connection_string]
def _connect(self, connection_string):
print(f"Connecting to {connection_string}")
self.connection_string = connection_string
conn1 = DatabaseConnection("db1.example.com")
conn2 = DatabaseConnection("db1.example.com") # Returns same instance
This object pool implementation:
Benefits of object pooling:
In metaclasses, __new__ controls class creation (rather than
instance creation).
class MetaLogger(type):
def __new__(mcls, name, bases, namespace):
print(f"Creating class {name}")
# Add a class-level logger
namespace['logger'] = logging.getLogger(name)
return super().__new__(mcls, name, bases, namespace)
class User(metaclass=MetaLogger):
pass
print(User.logger) #
Metaclass __new__ differs from regular __new__:
| Regular __new__ | Metaclass __new__ |
|---|---|
| Creates instances | Creates classes |
| Receives cls | Receives mcls (metaclass) |
| Returns instance | Returns class |
Common metaclass uses:
When working with __new__, keep these guidelines in mind:
__new__ unnecessarily - Most classes only need __init____init__ may not run - If __new__ returns an existing instance__new__ behavior - It's non-obvious to other developers
The __new__ method provides low-level control over object
creation in Python. While not needed for everyday programming, understanding
__new__ is essential for advanced Python patterns like:
Use it judiciously when you need precise control over instance creation, but
prefer __init__ for regular initialization tasks.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.