To understand and use Python's __new__ method effectively, let’s break down its purpose, key differences from __init__, and common use cases with examples.
What is __new__?
__new__ is a class-level method responsible for creating and returning a new instance of a class. It is called before __init__ (which initializes the instance).
Key Differences from __init__:
__new__ |
__init__ |
|---|---|
| Creates the instance | Initializes the instance |
Takes cls (class) as the first argument |
Takes self (instance) as the first argument |
| Must return an instance (or another object) | No return value (void) |
| Called once per instance creation | Called once per instance (only if __new__ returns an instance of the class) |
Basic Syntax
class MyClass:
def __new__(cls, *args, **kwargs):
# Create the instance using parent class's __new__
instance = super().__new__(cls)
# Optional: Custom logic before returning
return instance # Must return the instance!
def __init__(self, *args, **kwargs):
# Initialize the instance
pass
Common Use Cases
1. Singleton Pattern
Ensure only one instance of a class exists.
class Singleton:
_instance = None
_initialized = False # Track if __init__ was called
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, name):
if not self._initialized:
self.name = name
self._initialized = True
# Test
s1 = Singleton("First")
s2 = Singleton("Second")
print(s1.name) # Output: First (same instance)
print(s1 is s2) # Output: True
2. Factory Pattern
Return instances of different subclasses based on input.
class Shape:
def __new__(cls, shape_type, *args):
if shape_type == "circle":
return Circle(*args)
elif shape_type == "square":
return Square(*args)
raise ValueError("Unknown shape type")
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self): return 3.14 * self.radius**2
class Square:
def __init__(self, side):
self.side = side
def area(self): return self.side**2
# Test
circle = Shape("circle",5)
print(circle.area()) # Output:78.5
square = Shape("square",4)
print(square.area()) # Output:16
3. Immutable Objects
For objects that can’t be modified after creation (like tuples).
class ImmutablePoint:
def __new__(cls, x, y):
instance = super().__new__(cls)
instance._x = x # Set attributes in __new__ (since __init__ can't change them later)
instance._y = y
return instance
@property # Read-only access
def x(self): return self._x
@property
def y(self): return self._y
# Test
p = ImmutablePoint(1,2)
print(p.x) # Output: 1
# p.x =3 → AttributeError (no setter)
Key Notes
- Return Value: Always return an instance (or another object). If
__new__returnsNone,__init__won’t be called. - Parent Call: Use
super().__new__(cls)to create the base instance (unless you’re returning a different type). - Subclass Compatibility: If overriding
__new__in a subclass, ensure it works with parent classes (e.g.,object.__new__expectsclsas the first argument).
By mastering __new__, you gain fine-grained control over instance creation, enabling patterns like singletons, factories, and immutable objects.


作者声明:本文包含人工智能生成内容。