Python中__init__ 和 __new__ 的区别是什么?
在 Python 中,__new__ 和 __init__ 是对象创建过程中两个非常重要但角色完全不同的“魔术方法”。
简单的一句话总结:__new__ 负责“生”孩子(创建对象),__init__ 负责“穿”衣服(初始化对象)。
以下是详细的区别对比:
1. 核心区别表
| 特性 | __new__ |
__init__ |
|---|---|---|
| 功能 | 创建并返回一个实例对象 | 初始化已经创建好的实例对象 |
| 类型 | 这是一个类方法 (Class Method),第一个参数是 cls |
这是一个实例方法 (Instance Method),第一个参数是 self |
| 执行顺序 | 先执行。它是对象实例化的第一步 | 后执行。它在 __new__ 返回实例后才被调用 |
| 返回值 | 必须返回一个实例 (通常是 super().__new__(cls)) |
不需要返回值 (即返回 None) |
| 调用条件 | 每次实例化类时都会自动调用 | 只有当 __new__ 返回了当前类的实例时,__init__ 才会被调用 |
2. 代码演示执行顺序
python
class Person:
def __new__(cls, name):
print(f"1. __new__ 被调用: 正在创建类 {cls.__name__} 的实例")
# 必须调用父类的 __new__ 来真正分配内存创建对象
instance = super().__new__(cls)
return instance
def __init__(self, name):
print(f"2. __init__ 被调用: 正在初始化对象,名字是 {name}")
self.name = name
# 实例化对象
p = Person("Alice")
输出结果:
plaintext
1. __new__ 被调用: 正在创建类 Person 的实例
2. __init__ 被调用: 正在初始化对象,名字是 Alice
3. 关键细节与“陷阱”
最重要的机制在于:__init__ 的触发依赖于 __new__ 的返回值。
如果 __new__ 没有返回当前类的实例(例如返回了 None 或者返回了其他类的实例),那么 __init__ 根本不会被执行。
python
class NoInit:
def __new__(cls):
print("New 执行了")
return None # 没有返回实例
def __init__(self):
print("Init 执行了") # 这行永远不会打印
obj = NoInit()
# 输出: New 执行了
4. 什么时候需要使用 __new__?
在 99% 的日常开发中,你只需要用 __init__。但在以下几种高级场景中,必须使用 __new__:
A. 继承不可变类型 (Immutable Types)
如果你想继承 Python 的内置不可变类型(如 int, str, tuple)并修改其行为,必须在 __new__ 中处理。因为一旦对象在 __new__ 中创建完成(对于不可变类型),你就无法在 __init__ 中修改它的值了。
例子:创建一个永远是正数的整数类
python
class PositiveInt(int):
def __new__(cls, value):
# 在创建对象之前修改值
value = abs(value)
return super().__new__(cls, value)
# 这里写 __init__ 是没用的,因为 int 是不可变的,
# self 已经被创建出来了,无法再修改其数值。
i = PositiveInt(-10)
print(i) # 输出: 10
B. 单例模式 (Singleton Pattern)
单例模式要求一个类只能有一个实例。我们可以利用 __new__ 来控制对象的创建过程:如果实例已存在,直接返回旧实例;如果不存在,才创建新实例。
python
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 (说明是同一个对象)
C. 元类编程 (Metaclasses)
在编写元类时,__new__ 用于控制类的创建过程(注意:这里是创建“类”这个对象,而不是类的实例)。
总结
__new__是构造器(Constructor),它负责生。__init__是初始化器(Initializer),它负责养。- 如果你不需要控制对象的创建过程(内存分配、单例控制、不可变类型修改),请只使用
__init__。