Python __new__ Method

Complete guide to Python's __new__ method covering object creation, customization, and advanced patterns.

Python __new__ Method

Python new Method

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.

Understanding new Basics

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

  2. $1

  3. $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

Customizing Object Creation

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

Implementing the Singleton Pattern

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

  2. $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

Creating Immutable Objects

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

  2. $1

  3. $1

Subclassing Built-in Types

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

Object Pooling Pattern

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

  2. $1

  3. $1

  4. $1

Benefits of object pooling:

  • Reduces resource-intensive object creation

  • Limits total number of expensive resources (like DB connections)

  • Provides centralized management of instances

Metaclass new Method

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

Best Practices and Pitfalls

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

Conclusion

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.

Source References

Author

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.

ad ad