Python 中的 __new__深度解析
__new__是 Python 中最底层的对象创建机制,它比__init__更早被调用,真正负责分配并返回对象实例。理解它是掌握元类、单例、不可变类型定制等高级特性的基础。
一、__new__vs__init__的本质区别
classFoo:def__new__(cls,*args,**kwargs):print(f"[__new__] 分配内存,cls={cls}")instance=super().__new__(cls)# 创建实例returninstance# 必须 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)ifisinstance(obj,cls):# 只有返回 cls 的实例才调 __init__obj.__init__(*args,**kwargs)returnobj下面是完整的对象创建生命周期:—
三、最重要的使用场景
1. 单例模式(Singleton)
classSingleton:_instance=Nonedef__new__(cls,*args,**kwargs):ifcls._instanceisNone:cls._instance=super().__new__(cls)returncls._instance# 始终返回同一个实例a=Singleton()b=Singleton()print(aisb)# True2. 定制不可变类型
str、int、tuple等不可变类型必须在__new__中完成初始化,因为一旦创建就无法修改:
classUpperStr(str):def__new__(cls,value):returnsuper().__new__(cls,value.upper())# ⚠️ 不能在 __init__ 里改,str 是不可变的s=UpperStr("hello")print(s)# HELLOprint(type(s))# <class '__main__.UpperStr'>3. 工厂模式 —— 根据参数返回不同类型
classShape:def__new__(cls,kind,*args):subclasses={"circle":Circle,"rect":Rect}target_cls=subclasses.get(kind,cls)returnsuper().__new__(target_cls)classCircle(Shape):passclassRect(Shape):passs=Shape("circle")print(type(s))# <class '__main__.Circle'>4. 元类(Metaclass)中的__new__
元类的__new__控制类本身的创建(不是实例的创建):
classMeta(type):def__new__(mcs,name,bases,namespace):# 在类定义时,自动把所有方法名转大写new_ns={k.upper()ifnotk.startswith('_')elsek:vfork,vinnamespace.items()}returnsuper().__new__(mcs,name,bases,new_ns)classFoo(metaclass=Meta):defhello(self):return"hi"Foo().HELLO()# "hi" — 方法被重命名了四、常见陷阱
陷阱1:忘记return
classBad:def__new__(cls):super().__new__(cls)# 没有 return!→ 返回 None# __init__ 不会被调用,obj 是 None陷阱2:__init__的参数必须与__new__一致
# Python 会同时把参数传给 __new__ 和 __init__# 若签名不匹配会报 TypeErrorclassOk:def__new__(cls,x,y):# 接受 x, yreturnsuper().__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__。日常开发中最实用的三个场景是:单例、不可变类型继承、工厂方法。
