__new__和__init__的区别是什么
在 Python 中,__new__
和 __init__
都是与对象创建相关的特殊方法,但它们的作用和调用时机截然不同。简单来说:__new__
负责创建实例,__init__
负责初始化实例。
核心区别对比
特性 | __new__ | __init__ |
---|---|---|
作用 | 创建类的实例对象(分配内存) | 初始化已创建的实例(设置属性等) |
调用时机 | 实例创建前被调用 | 实例创建后(__new__ 返回实例后)被调用 |
参数 | 第一个参数是 cls (类本身) | 第一个参数是 self (刚创建的实例) |
返回值 | 必须返回一个实例对象(通常是当前类) | 无返回值(若返回非 None 会报错) |
方法类型 | 类方法(隐式被 @classmethod 修饰) | 实例方法 |
是否必须实现 | 非必须(默认调用父类的 __new__ ) | 非必须(无自定义初始化逻辑时可省略) |
详细解析
1. __new__
:创建实例的 “构造器”
__new__
是 Python 中真正负责创建实例对象的方法。当你调用 ClassName()
创建实例时,Python 会先调用 __new__
方法,为对象分配内存并返回一个实例。
- 参数:第一个参数是
cls
(表示当前类),后续参数与类的构造参数一致。 - 返回值:必须返回一个实例(通常是通过
super().__new__(cls)
调用父类的__new__
来创建)。如果__new__
没有返回实例,__init__
不会被调用。
示例:
python
运行
class MyClass:def __new__(cls, *args, **kwargs):print("__new__ 被调用,创建实例")# 调用父类的__new__创建并返回实例instance = super().__new__(cls)return instancedef __init__(self, name):print("__init__ 被调用,初始化实例")self.name = name# 创建实例
obj = MyClass("test")
# 输出:
# __new__ 被调用,创建实例
# __init__ 被调用,初始化实例
2. __init__
:初始化实例的 “初始化器”
__init__
是在 __new__
成功创建实例后被调用的方法,用于初始化实例的属性(如设置初始值、绑定方法等)。它不负责创建实例,而是 “修饰” 已存在的实例。
- 参数:第一个参数是
self
(即__new__
返回的实例),后续参数与类的构造参数一致。 - 返回值:必须为
None
(若返回其他值会抛出TypeError
)。
示例:
python
运行
class Person:def __init__(self, name, age):# 初始化实例属性self.name = nameself.age = agep = Person("Alice", 30)
print(p.name) # 输出:Alice(__init__ 初始化的属性)
典型使用场景
__new__
的常见用途:
子类化不可变类型:如
int
、str
、tuple
等不可变类型,由于它们创建后无法修改,需在__new__
中定制实例(__init__
无法做到)。python
运行
class PositiveInt(int):def __new__(cls, value):# 确保创建的int实例是正数return super().__new__(cls, abs(value))num = PositiveInt(-5) print(num) # 输出:5(通过__new__修改了初始值)
实现单例模式:控制类只能创建一个实例(每次调用类时返回同一个实例)。
python
运行
class Singleton:_instance = None # 保存唯一实例def __new__(cls):if cls._instance is None:cls._instance = super().__new__(cls)return cls._instancea = Singleton() b = Singleton() print(a is b) # 输出:True(a和b是同一个实例)
__init__
的常见用途:
- 为实例设置初始属性(最常用场景)。
- 执行实例创建后的初始化逻辑(如连接数据库、加载配置等)。
总结
__new__
是 “创建者”,负责实例的诞生(分配内存、返回实例)。__init__
是 “化妆师”,负责实例的初始化(设置属性、初始化状态)。- 两者协同完成对象的创建流程:
__new__
先创建实例,__init__
再初始化它。
日常开发中,__init__
使用率远高于 __new__
,只有在需要控制实例创建过程(如不可变类型子类化、单例等)时,才需要重写 __new__
。