__new__返回实例类型必须与类一致,否则跳过__init__;__init__中不能重赋值self;单例需在__new__缓存并返回旧实例;不可变类型构造必须在__new__完成。

为什么__new__返回的实例类型必须和类一致
如果__new__返回了非当前类或其子类的实例(比如直接返回int(42)或object()),Python 会跳过__init__调用——这不是 bug,是语言设计:只有当__new__返回的是本类实例时,解释器才认为“构造完成”,进而触发__init__。常见错误是写成:
def __new__(cls, value):
return super().__new__(int) # 错!返回 int 实例,__init__ 不会被调用正确做法是确保返回cls的实例:
def __new__(cls, value):
instance = super().__new__(cls)
return instance如果你真要代理到其他类型(如单例、缓存、不可变封装),必须显式调用__init__或改用__call__在元类中控制。
__init__里不能给self重新赋值为新对象
__init__的self参数是__new__返回的对象引用,它已经确定了内存地址和类型。你不能在__init__里写self = SomeOtherClass()——这只会让局部变量self指向别处,原对象不变,且后续所有属性赋值都作用在旧对象上。
立即学习“Python免费学习笔记(深入)”;
典型误用场景:
- 想“转换类型”:比如传入字符串就转成
int,但又想保留类接口 → 应该在__new__中决定返回哪个类的实例,或用工厂函数 - 想避免重复初始化:比如检查参数是否已存在对应实例 → 这属于对象创建逻辑,应在
__new__中做缓存/查表
记住:__init__只负责“填充”已有实例,不负责“生成”或“替换”。
单例模式下__new__必须缓存并返回旧实例
单例不是靠__init__控制的,因为每次调用类都会执行__new__→__init__流程。__init__反复执行会导致状态被覆盖。真正可靠的单例必须在__new__中拦截:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance注意两点:
- 缓存的是
cls._instance,不是self(self还没诞生) - 必须用
super().__new__(cls)而非object.__new__(cls),否则绕过父类__new__可能破坏继承链(比如某些框架类重写了__new__)
如果类有参数,还要在__new__中处理**kwargs或校验参数一致性,否则多次不同参数调用可能导致状态混乱。
不可变类型(如str、tuple子类)必须在__new__中完成构造
__init__无法修改不可变对象的值。例如自定义一个带校验的PositiveInt:
class PositiveInt(int):
def __new__(cls, value):
if value < 0:
raise ValueError("must be positive")
return super().__new__(cls, value) # ✅ 在 __new__ 中传入合法值下面这种写法是错的:
def __init__(self, value): # ❌ int 实例一旦创建就不能改,__init__ 里 self = ... 无效
if value < 0:
raise ValueError(...)原因:父类int的__new__已经把值固化进对象了。__init__只能设置额外属性(如self.source = "user_input"),不能动核心值。所以所有对值的校验、转换、截断等操作,必须放在__new__里完成。
容易被忽略的是:即使你没显式定义__new__,Python 也会用默认的object.__new__,而它不做任何值处理——所以一旦涉及不可变类型的定制,__new__不是可选项,是必选项。


















