Complete guide to Python's __new__ method covering object creation, customization, and advanced patterns.
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.
basic_new.py
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:
$1
$1
$1
Key characteristics of new:
It’s a static method (though no decorator needed)
Must return an instance (usually of cls)
Can return instances of other classes (unlike init)
Rarely needs to be overridden in regular classes
The new method allows complete control over instance creation. This example shows how to customize what gets created.
custom_creation.py
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:
We can completely bypass normal instance creation by returning something other than an instance of our class
We can add attributes to the instance before init is called
The init method only runs if new returns an instance of the class
Practical applications include:
Input validation before object creation
Adding creation metadata to instances
Implementing object pooling or caching
The new method is perfect for implementing the Singleton pattern, which ensures a class has only one instance.
singleton.py
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:
$1
$1
Using an initialized flag to prevent init from running multiple times
Important considerations:
The initialized flag prevents re-initialization
Thread-safe implementations require additional locking
Subclassing Singletons requires special consideration
new can be used to create immutable objects by controlling attribute assignment.
immutable.py
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 modifications
Why this works:
$1
$1
$1
new is essential when subclassing immutable built-in types like tuple or str.
subclass_tuple.py
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
We pass the immutable data to the parent class’s new
Additional attributes must be set in new before the object becomes immutable
Common use cases:
Adding metadata to built-in types
Creating specialized versions of strings, numbers, or tuples
Implementing custom immutable collections
new can implement object pooling to reuse instances instead of creating new ones.
object_pool.py
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:
$1
$1
$1
$1
Benefits of object pooling:
Reduces resource-intensive object creation
Limits total number of expensive resources (like DB connections)
Provides centralized management of instances
In metaclasses, new controls class creation (rather than instance creation).
meta_new.py
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:
Class registration systems
Automatic addition of methods/properties
Enforcing coding standards
API endpoint generation
When working with new, keep these guidelines in mind:
Don’t override new unnecessarily - Most classes only need init
Always call super().new - Unless you have a specific reason not to
Remember init may not run - If new returns an existing instance
Document your new behavior - It’s non-obvious to other developers
Consider thread safety - For patterns like Singleton or object pooling
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:
Custom immutable objects
Singleton implementation
Object pooling
Subclassing built-in types
Metaclass programming
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.