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

步骤:

  1. MyClass(10) 触发 __new__(cls, 10) 调用,返回一个新实例(对象)。
  2. 接着 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__ 的典型场景

  1. 不可变类型的子类化(如 str, tuple, int)时,需要在创建时修改值。
class UpperStr(str):
    def __new__(cls, value):
        # 在创建字符串对象之前将值转为大写
        return super().__new__(cls, value.upper())

s = UpperStr("hello")
print(s)  # "HELLO"
  1. 实现单例模式(确保一个类只有一个实例)。
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
  1. 返回缓存的对象(例如对象池)。

__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. 实际底层流程

  1. obj = MyClass(args) 被解释器执行。
  2. 解释器调用 MyClass.__new__(MyClass, args)
  3. __new__ 返回一个实例(假设为 inst)。
  4. 如果 inst 确实是 MyClass 类型(或子类),解释器调用 MyClass.__init__(inst, args)
  5. 最终 obj 被绑定到 inst

8. 总结对比

特性 __new__ __init__
角色 构造器(创建对象) 初始化器(配置对象)
第一个参数 cls(类) self(实例)
返回值 必须返回一个对象(通常是实例) 必须返回 None
调用时机 在实例创建之前 在实例创建之后
常见用途 不可变子类、单例、对象池 设置实例属性、初始化状态
可覆盖性 可完全控制对象创建 只能对已有对象初始化

核心要点__new__ 制造对象,__init__ 装修对象。在大多数日常编码中,你只需要 __init__;当需要对对象创建过程进行底层控制时,才需要覆盖 __new__

Python中的 __new__ 与 __init__ 方法区别与协同工作 在Python中,当我们创建类的实例时,会涉及两个特殊的魔术方法: __new__ 和 __init__ 。它们分别在对象创建的不同阶段被调用,协同完成实例的构造。 1. 总体作用 __new__ :负责 创建并返回 一个新的实例(对象)。它是一个静态方法(虽然不需要显式声明为 @staticmethod ),第一个参数是 cls (要实例化的类本身)。 __init__ :负责 初始化 已创建好的实例。它是一个实例方法,第一个参数是 self (由 __new__ 返回的实例)。 简单来说: __new__ 是“构造函数”(constructor),负责制造一个“空对象”; __init__ 是“初始化函数”(initializer),负责给这个对象填充初始数据。 2. 调用顺序 输出: 步骤: MyClass(10) 触发 __new__(cls, 10) 调用,返回一个新实例(对象)。 接着 Python 自动调用 __init__(self, 10) ,其中 self 就是 __new__ 返回的实例。 3. __new__ 的深入理解 __new__ 必须返回一个对象(通常是 cls 的实例)。 如果不返回对象, __init__ 就不会被调用。 可以返回其他类的实例,这样 __init__ 会根据返回的实例类型调用。 4. __init__ 的限制 __init__ 不能有返回值(必须返回 None )。 它只是在已有对象上设置属性。 5. 使用场景区分 __new__ 的典型场景 : 不可变类型的子类化 (如 str , tuple , int )时,需要在创建时修改值。 实现单例模式 (确保一个类只有一个实例)。 返回缓存的对象 (例如对象池)。 __init__ 的典型场景 : 绝大部分情况下,我们只需要在 __init__ 中设置实例属性。 6. 协同工作时的参数传递 当调用 MyClass(args...) 时: 参数首先传递给 __new__(cls, args...) 。 __new__ 返回的实例,连同剩余参数再传递给 __init__(self, args...) 。 注意: __new__ 和 __init__ 的参数签名通常应保持一致(除了第一个参数不同)。 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__ 。