Python中的`__new__`与`__init__`方法区别与协同工作
字数 1626 2025-12-13 06:18:41
Python中的__new__与__init__方法区别与协同工作
在Python中,当我们创建类的实例时,会涉及两个特殊的魔术方法:__new__和__init__。它们分别在对象创建的不同阶段被调用,协同完成实例的构造。
1. 总体作用
__new__:负责创建并返回一个新的实例(对象)。它是一个静态方法(虽然不需要显式声明为@staticmethod),第一个参数是cls(要实例化的类本身)。__init__:负责初始化已创建好的实例。它是一个实例方法,第一个参数是self(由__new__返回的实例)。
简单来说:__new__是“构造函数”(constructor),负责制造一个“空对象”;__init__是“初始化函数”(initializer),负责给这个对象填充初始数据。
2. 调用顺序
class MyClass:
def __new__(cls, *args, **kwargs):
print("__new__ called")
instance = super().__new__(cls) # 调用父类的__new__创建实例
return instance
def __init__(self, value):
print("__init__ called")
self.value = value
obj = MyClass(10)
输出:
__new__ called
__init__ called
步骤:
MyClass(10)触发__new__(cls, 10)调用,返回一个新实例(对象)。- 接着 Python 自动调用
__init__(self, 10),其中self就是__new__返回的实例。
3. __new__ 的深入理解
__new__必须返回一个对象(通常是cls的实例)。- 如果不返回对象,
__init__就不会被调用。
class NoInitClass:
def __new__(cls):
print("__new__ returns None")
return None # 不返回实例
def __init__(self):
print("__init__ called") # 这行永远不会执行
obj = NoInitClass()
print(obj) # 输出 None
- 可以返回其他类的实例,这样
__init__会根据返回的实例类型调用。
class OtherClass:
pass
class Creator:
def __new__(cls):
print("Creating an instance of OtherClass")
return OtherClass()
obj = Creator()
print(type(obj)) # <class '__main__.OtherClass'>
4. __init__ 的限制
__init__不能有返回值(必须返回None)。- 它只是在已有对象上设置属性。
5. 使用场景区分
__new__ 的典型场景:
- 不可变类型的子类化(如
str,tuple,int)时,需要在创建时修改值。
class UpperStr(str):
def __new__(cls, value):
# 在创建字符串对象之前将值转为大写
return super().__new__(cls, value.upper())
s = UpperStr("hello")
print(s) # "HELLO"
- 实现单例模式(确保一个类只有一个实例)。
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b) # True
- 返回缓存的对象(例如对象池)。
__init__ 的典型场景:
- 绝大部分情况下,我们只需要在
__init__中设置实例属性。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
6. 协同工作时的参数传递
当调用 MyClass(args...) 时:
- 参数首先传递给
__new__(cls, args...)。 __new__返回的实例,连同剩余参数再传递给__init__(self, args...)。- 注意:
__new__和__init__的参数签名通常应保持一致(除了第一个参数不同)。
class Example:
def __new__(cls, x, y):
print(f"__new__ got x={x}, y={y}")
return super().__new__(cls)
def __init__(self, x, y):
print(f"__init__ got x={x}, y={y}")
self.x = x
self.y = y
e = Example(1, 2)
7. 实际底层流程
obj = MyClass(args)被解释器执行。- 解释器调用
MyClass.__new__(MyClass, args)。 __new__返回一个实例(假设为inst)。- 如果
inst确实是MyClass类型(或子类),解释器调用MyClass.__init__(inst, args)。 - 最终
obj被绑定到inst。
8. 总结对比
| 特性 | __new__ |
__init__ |
|---|---|---|
| 角色 | 构造器(创建对象) | 初始化器(配置对象) |
| 第一个参数 | cls(类) |
self(实例) |
| 返回值 | 必须返回一个对象(通常是实例) | 必须返回 None |
| 调用时机 | 在实例创建之前 | 在实例创建之后 |
| 常见用途 | 不可变子类、单例、对象池 | 设置实例属性、初始化状态 |
| 可覆盖性 | 可完全控制对象创建 | 只能对已有对象初始化 |
核心要点:__new__ 制造对象,__init__ 装修对象。在大多数日常编码中,你只需要 __init__;当需要对对象创建过程进行底层控制时,才需要覆盖 __new__。