Python中__new__和__init__的区别与联系
已于 2025年10月12日 11:07 修改
访问次数:0
当然可以 👍
下面是你目前掌握的 __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)