Python __new__ Method
Last modified April 8, 2025
This comprehensive guide explores Python's __new__
method, the
special method responsible for object creation. We'll cover basic usage,
immutable objects, singletons, metaclasses, and practical examples.
Basic Definitions
The __new__
method is a static method that creates and returns a
new instance of a class. It is called before __init__
and is
responsible for object allocation.
Key characteristics: it must accept the class as first argument (conventionally
named cls
), returns the new instance, and can be overridden to
customize object creation. Unlike __init__
, it controls creation.
Basic __new__ Implementation
Here's the simplest implementation showing __new__
's role in the
object creation lifecycle. It demonstrates how it works with __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) print(obj.value)
This example shows the object creation sequence. __new__
creates
the instance, then __init__
initializes it. The output would show
"__new__ called" before "__init__ called".
The super().__new__(cls)
call is crucial - it creates the actual
instance using the parent class's __new__
method (usually
object.__new__
).
Creating Immutable Objects
__new__
is essential when creating immutable types like tuples or
custom immutable classes, where modification after creation should be prevented.
class ImmutablePoint: def __new__(cls, x, y): instance = super().__new__(cls) instance._x = x instance._y = y return instance @property def x(self): return self._x @property def y(self): return self._y def __repr__(self): return f"Point({self.x}, {self.y})" point = ImmutablePoint(3, 4) print(point) # point.x = 5 # Would raise AttributeError
This immutable point class sets coordinates during creation via __new__
and exposes them as read-only properties. Attempting to modify them would raise
an AttributeError
.
The instance variables are set in __new__
before returning the
instance, making them part of the initial object state. This pattern is common
for immutable objects.
Implementing the Singleton Pattern
The Singleton pattern ensures a class has only one instance. __new__
can enforce this by controlling instance creation.
class Singleton: _instance = None def __new__(cls): if cls._instance is None: print("Creating new instance") cls._instance = super().__new__(cls) return cls._instance def __init__(self): print("Initializing Singleton") s1 = Singleton() s2 = Singleton() print(s1 is s2) # True
This Singleton implementation stores the single instance in a class variable.
__new__
checks if it exists before creating a new one. All
constructor calls return the same instance.
Note that __init__
is called each time, which might reinitialize
the instance. To prevent this, you could add another flag or restructure the
code.
Customizing Object Creation with Arguments
__new__
can inspect arguments and decide whether/how to create an
instance, enabling advanced creation patterns.
class LimitedInstances: _count = 0 MAX_INSTANCES = 3 def __new__(cls, *args, **kwargs): if cls._count >= cls.MAX_INSTANCES: raise RuntimeError(f"Cannot create more than {cls.MAX_INSTANCES} instances") cls._count += 1 return super().__new__(cls) def __del__(self): type(self)._count -= 1 objs = [LimitedInstances() for _ in range(3)] # Works # LimitedInstances() # Raises RuntimeError
This class limits the number of live instances to 3. __new__
checks
the count before allowing creation. The __del__
method decreases
the count when instances are garbage collected.
This pattern is useful for resource-limited scenarios like database connections or thread pools where you want to enforce instance limits.
Metaclass __new__ Method
In metaclasses, __new__
controls class creation (rather than instance
creation), allowing dynamic class modification.
class Meta(type): def __new__(mcls, name, bases, namespace): print(f"Creating class {name}") namespace['version'] = 1.0 return super().__new__(mcls, name, bases, namespace) class MyClass(metaclass=Meta): pass print(MyClass.version) # 1.0
This metaclass adds a version
attribute to every class it creates.
The metaclass's __new__
modifies the class namespace before the
class is constructed.
Metaclass __new__
receives different arguments: the metaclass
itself, the class name, base classes, and the namespace dictionary containing
class attributes.
Best Practices
- Always call super().__new__: Unless intentionally blocking creation
- Return correct type: Ensure returned object is an instance of cls
- Consider __init__: Changes in __new__ might affect initialization
- Document behavior: Clearly document any special creation logic
- Prefer __init__ when possible: Only use __new__ when necessary
Source References
Author
List all Python tutorials.