人人都会AI编程

构造与析构:__init__、__new__、__del__

更新时间:2026-07-12

在 Python 面向对象编程中,对象的“生”与“死”由三个特殊方法控制:new 负责创建对象,init 负责初始化对象,del 在对象即将被销毁时调用。理解它们的执行顺序和适用场景,是写出健壮 Python 类的基础。

new:对象创建

  • 调用时机:在实例化一个类时,最先被调用。它是一个静态方法,用来生成并返回一个新的实例对象。
  • 默认行为:如果没有重写,会调用父类(通常是 object)的 new,分配内存并返回一个空的实例。
  • 什么时候需要重写
  • 单例模式:确保一个类只有一个实例,在 new 中控制实例创建。
  • 继承不可变类型:比如你想自定义一个 inttuple 的子类,需要在 new 中创建实例,因为不可变对象在 init 阶段已经无法修改值。
  • 典型代码
  class Singleton:
      _instance = None
      def __new__(cls, *args, **kwargs):
          if cls._instance is None:
              cls._instance = super().__new__(cls)
          return cls._instance
  

init:对象初始化

  • 调用时机:紧跟在 new 返回一个实例之后被调用。new 创建了空壳,init 负责填充属性。
  • 核心作用:对实例进行初始化设置,将传入的参数绑定到实例属性上。这是最常见、最熟悉的构造函数“代言人”。
  • 注意事项
  • init 不能返回任何值(或只能返回 None),否则会引发 TypeError
  • 如果 new 返回的不是当前类的实例,则 init 根本不会被调用。
  • 最佳实践
  • 始终在 init 中明确所有实例属性,提高代码可读性。
  • 复杂初始化逻辑可以单独拆分为私有方法,比如 _initialize,避免 init 过度臃肿。

del:析构函数

  • 调用时机:当对象的引用计数归零,垃圾回收器即将销毁对象时调用。它在对象“临终”前执行一些清理工作。
  • 常见用途
  • 关闭文件、网络连接、数据库连接等外部资源。
  • 调试时输出对象销毁信息,辅助排查内存泄漏。
  • 重大陷阱与避坑指南
  • 不要依赖它做关键清理del 的调用时机不确定,可能在程序退出时仍未被调用,而且一旦程序崩溃提前终止,del 可能根本不会执行。推荐使用上下文管理器(with 语句)或显式 close() 方法来管理资源。
  • 避免在 del 中访问其他对象:当对象被销毁时,其他对象可能已经消失,容易引发异常。
  • 循环引用会推迟 del 调用:如果对象间存在循环引用,垃圾回收器需要额外的标记-清除周期才能回收,del 的执行会延迟。Python 3.4 之后,循环引用中的 del 方法在程序退出时仍会被尝试调用,但依然不建议依赖它。
  • 典型用法(谨慎使用)
  class FileManager:
      def __init__(self, filename):
          self.file = open(filename, 'w')
      
      def __del__(self):
          self.file.close()
  

更好的做法是用 with 配合 enter/exit

一个体现三者关系的例子

class Demo:
    def __new__(cls, *args, **kwargs):
        print("1. __new__ 创建实例")
        instance = super().__new__(cls)
        return instance

    def __init__(self, value):
        print("2. __init__ 初始化实例")
        self.value = value

    def __del__(self):
        print("3. __del__ 对象即将被销毁")

# 执行
d = Demo(42)
# 输出:
# 1. __new__ 创建实例
# 2. __init__ 初始化实例

del d    # 如果此时没有其他引用,可能会触发 __del__
# 输出: 3. __del__ 对象即将被销毁

实用总结

  • 日常开发中 95% 以上的类只需要写 init,不需要碰 newdel
  • 需要控制实例创建(如单例、不可变类型子类化)时用 new
  • 资源清理请优先使用上下文管理器(实现 enter/exit),忘掉 del 是更安全的选择。