Python中__new__和__init__的区别与联系

当然可以 👍

下面是你目前掌握的 __new__ 与 __init__ 的完整知识总结,帮你形成一个系统的框架。



🧱 Python 对象创建的双阶段机制:__new__ vs __init__



一、两者的根本区别

对比项__new____init__
调用时机在实例创建之前调用在实例创建之后调用
职责负责创建对象(分配内存)负责初始化对象(设置属性)
第一个参数cls(类本身)self(新创建的实例)
返回值必须返回一个实例对象只能返回 None
被调用者Python 解释器 调用由解释器在 __new__ 返回对象后自动调用
常见用途单例模式、不可变类型(int, str, tuple)的子类化普通对象属性初始化、构造逻辑
是否常用很少重写经常重写(构造函数)


二、执行流程(你调用 MyClass(10) 时)

Python 内部执行步骤:
1️⃣ 调用 MyClass.__new__(MyClass, 10)
     → 负责创建对象(返回实例)
2️⃣ 调用 MyClass.__init__(instance, 10)
     → 负责初始化实例属性
3️⃣ 返回完整初始化好的对象

图示:

MyClass(10)
   │
   ▼
__new__(cls, 10)
   │ 创建实例
   ▼
__init__(self, 10)
   │ 初始化属性
   ▼
返回完整对象


三、__new__ 的参数:*args**kwargs

问题解释
谁传入的?Python 解释器 在执行 MyClass(...) 时自动传入
什么时候传入?在调用 __new__(创建对象)时
为什么要写上?为了让 __new__ 能兼容 __init__ 的所有参数
为什么调用 super().__new__(cls) 时不传参数?因为大多数父类(如 object)不使用这些参数(除非继承不可变类型)

例子:

def __new__(cls, *args, **kwargs):
    instance = super().__new__(cls)  # 通常不需要传参
    return instance


四、super().__new__ 是否需要参数?

父类类型是否需要传入 *args**kwargs原因
可变类型(如 object, list, dict❌ 不需要父类的 __new__ 不使用这些参数
不可变类型(如 int, str, tuple✅ 需要父类的 __new__ 用参数决定实例的值

示例:

# 可变类,不需要传参
super().__new__(cls)

# 不可变类,必须传参
super().__new__(cls, value)


五、常见使用场景

✅ 普通类:只写 __init__

class Person:
    def __init__(self, name):
        self.name = name

✅ 单例模式(控制实例创建)

class Singleton:
    _instance = None
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

✅ 不可变类型的继承

class MyInt(int):
    def __new__(cls, value):
        return super().__new__(cls, value + 1)


六、典型错误与注意点

错误场景原因
__new__ 没有返回实例Python 会抛 TypeError: __init__() should return None, not '...'
忘记写 *args, **kwargs如果构造传参,会报 TypeError
修改不可变类型的属性放在 __init__无效,必须在 __new__ 中操作
单例模式中重复初始化即使 __new__ 返回同一实例,__init__ 仍会执行,每次实例化都会调用一次


七、一句话总结

__new__ 决定“造不造对象”,__init__ 决定“造好的对象怎么用”。 __new__ 是 对象工厂, __init__ 是 对象装修工。
文章标签:

评论(0)