【问题标题】:Destructor in metaclass Singleton object元类 Singleton 对象中的析构函数
【发布时间】:2016-06-25 05:54:50
【问题描述】:

我正在通过元类方法修改一个使用单例模式的遗留库。

继承自 type 的 Singleton 类定义了 de __call__ 函数。

现在,我使用这个库的单例对象永远不会被删除。我在单例类中定义了__del__ 方法,并且从未调用过该函数。

澄清:我已经实现了一个名为Singleton 的(元)类,它被多个类使用,使用Singleton 作为__metaclass__

例如,我有class A(object),它有__metaclass__ = Singleton。 A 类有几个成员,当我的程序结束并且 A 对象(唯一可以存在的对象)被销毁时,我希望这些成员被销毁。

我尝试在A 类中定义__del__ 方法,但它不起作用。

【问题讨论】:

  • 这可能有助于理解为什么你需要销毁一个单例。你只有一个。 (对吧?你说的好像你有多个单例,这令人困惑。)如果你只有一个,那么需要销毁它是不寻常的。
  • 你是对的。我正在编辑我的问题
  • @senderle,在某些测试场景中,创建一个可以自行清理的夹具是有益的,而在生产中只有该对象的单个实例才有意义,并且通常不需要清理。

标签: python singleton destructor metaclass


【解决方案1】:

第 1 点:__del__() 不能在进程退出时调用

首先要说的是

不能保证在解释器退出时为仍然存在的对象调用 __del__() 方法。

来自the python data model docs。因此,您不应该依赖它来整理您需要在退出时整理的状态,并且在最高级别,这就是您的__del__() 可能不会被调用的原因。这就是atexit 的用途。

第 2 点:可预测的对象生命周期是 python 中的一个实现细节

接下来要说的是,虽然 CPython 使用引用计数来检测对象可以被释放而无需使用垃圾收集器(导致更可预测的 CPU 影响和潜在的更高效的应用程序),但它只需要一个循环引用、一个未清除的异常、一个被遗忘的闭包或一个要中断的不同 python 实现,因此您应该真正真正认真考虑是否要依赖 __del__() 在特定点被调用.

第 3 点:单例实现通常维护对单例实例的全局引用

听上去,我猜你的单例元类(本身就是一个单例...)在第一次调用__call__() 时会保留你的单例实例。由于元类没有被释放,因为它属于模块,它本身由sys.modules 保留,因此该引用不会在程序终止时消失,因此即使保证及时整理所有外部引用单身人士被释放,你的__del__() 不会被调用。

你可以尝试什么

  1. 在创建单例实例时添加 atexit 处理程序,以便在进程退出时进行必要的整理。
  2. 如果需要,也可以在 __del__() 方法中进行整理。例如,您可以决定整洁/未来的可扩展性(例如,将单例复数化),您希望单例实例在不再使用时自行整理。
    • 如果您实现了一个 __del__() 方法,希望在正常程序执行期间完成整理,您可能还需要删除 atexit 处理程序。
  3. 如果您希望在没有人使用时清理您的单例,请考虑使用 weakref 将其存储在您的元类中,这样您就不会自己保留它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-10
    • 2014-06-27
    • 2016-01-26
    • 2018-09-01
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多