Python 中 __new__的实现示例
__new__ 是 Python 中最底层的对象创建机制,它比 __init__ 更早被调用,真正负责分配并返回对象实例。理解它是掌握元类、单例、不可变类型定制等高级特性的基础。
一、__new__vs__init__的本质区别
class Foo:
def __new__(cls, *args, **kwargs):
print(f"[__new__] 分配内存,cls={cls}")
instance = super().__new__(cls) # 创建实例
return instance # 必须 return!
def __init__(self, value):
print(f"[__init__] 初始化,self={self}")
self.value = value
obj = Foo(42)
# [__new__] 分配内存,cls=<class 'Foo'>
# [__init__] 初始化,self=<__main__.Foo object>
关键区别:
| __new__ | __init__ | |
|---|---|---|
| 调用时机 | 实例创建之前 | 实例创建之后 |
| 第一个参数 | cls(类本身) | self(已有实例) |
| 返回值 | 必须返回实例 | 必须返回 None |
| 职责 | 分配空间,构造对象 | 初始化属性 |
__init__ 只有在 __new__ 返回了 cls 的实例时才会被调用。若返回其他类型,__init__ 会被跳过。
二、__new__的签名与调用链
object.__new__(cls[, *args, **kwargs])
Python 内部执行 Foo(42) 的等价逻辑是:
# type.__call__ 的内部行为(伪代码)
def __call__(cls, *args, **kwargs):
obj = cls.__new__(cls, *args, **kwargs)
if isinstance(obj, cls): # 只有返回 cls 的实例才调 __init__
obj.__init__(*args, **kwargs)
return obj
下面是完整的对象创建生命周期:—
三、最重要的使用场景
1. 单例模式(Singleton)
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance # 始终返回同一个实例
a = Singleton()
b = Singleton()
print(a is b) # True
2. 定制不可变类型
str、int、tuple 等不可变类型必须在 __new__ 中完成初始化,因为一旦创建就无法修改:
class UpperStr(str):
def __new__(cls, value):
return super().__new__(cls, value.upper())
# ⚠️ 不能在 __init__ 里改,str 是不可变的
s = UpperStr("hello")
print(s) # HELLO
print(type(s)) # <class '__main__.UpperStr'>
3. 工厂模式 —— 根据参数返回不同类型
class Shape:
def __new__(cls, kind, *args):
subclasses = {"circle": Circle, "rect": Rect}
target_cls = subclasses.get(kind, cls)
return super().__new__(target_cls)
class Circle(Shape): pass
class Rect(Shape): pass
s = Shape("circle")
print(type(s)) # <class '__main__.Circle'>
4. 元类(Metaclass)中的__new__
元类的 __new__ 控制类本身的创建(不是实例的创建):
class Meta(type):
def __new__(mcs, name, bases, namespace):
# 在类定义时,自动把所有方法名转大写
new_ns = {k.upper() if not k.startswith('_') else k: v
for k, v in namespace.items()}
return super().__new__(mcs, name, bases, new_ns)
class Foo(metaclass=Meta):
def hello(self): return "hi"
Foo().HELLO() # "hi" — 方法被重命名了
四、常见陷阱
陷阱1:忘记 return
class Bad:
def __new__(cls):
super().__new__(cls) # 没有 return!→ 返回 None
# __init__ 不会被调用,obj 是 None
陷阱2:__init__ 的参数必须与 __new__ 一致
# Python 会同时把参数传给 __new__ 和 __init__
# 若签名不匹配会报 TypeError
class Ok:
def __new__(cls, x, y): # 接受 x, y
return super().__new__(cls)
def __init__(self, x, y): # 同样接受 x, y ✓
self.x, self.y = x, y
陷阱3:super().__new__ 的参数
- Python 3.3+ 后,
object.__new__和object.__init__中有一个接受了额外参数,另一个就会忽略多余参数(宽容机制) - 但自定义链中不要依赖这一行为,始终显式传递参数
五、__new__与__init_subclass__、__class_getitem__的关系
| 钩子 | 触发时机 | 典型用途 |
|---|---|---|
| __new__ | 每次实例化时 | 控制实例创建 |
| __init_subclass__ | 定义子类时 | 自动注册子类 |
| __class_getitem__ | Foo[int] 语法 | 泛型支持 |
| 元类 __new__ | 定义类本身时 | 修改类结构 |
总结
__new__ 的核心价值在于:在对象真正存在之前介入。当你需要控制的不是"对象初始化后的状态",而是"对象是哪个、是否创建、是什么类型"时,就该用 __new__。日常开发中最实用的三个场景是:单例、不可变类型继承、工厂方法。
到此这篇关于Python 中 __new__的实现示例的文章就介绍到这了,更多相关Python __new__内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


最新评论