我正在修改一个通过元类方法使用单例模式的遗留库。
Singleton类,继承自type
,定义了__call__
函数。
现在,我使用这个库的单例对象永远不会被删除。我在单例类中定义了 __del__
方法,但从未调用该函数。
澄清:我已经实现了一个名为 Singleton
的(元)类,它被多个类使用,使用 Singleton
作为 __metaclass__
。
例如,我有 class A(object)
,它有 __metaclass__ = Singleton
。 A 类有几个成员,我想在我的程序结束时销毁它们,并且 A 对象(唯一可以存在的对象)被销毁。
我尝试在 A
类中定义 __del__
方法,但它不起作用。
最佳答案
要点 1:__del__()
不能在进程退出时调用
首先要说的是
It is not guaranteed that
__del__()
methods are called for objects that still exist when the interpreter exits.
来自 the python data model docs .因此,您不应该依赖它来整理您需要在退出时整理的状态,并且在最高级别,这就是您的 __del__()
可能不会被调用的原因。这就是atexit
是为了。
要点2:可预测的对象生命周期是python中的一个实现细节
接下来要说的是,虽然 CPython 使用引用计数使其能够检测到无需使用垃圾收集器就可以释放对象(导致更可预测的 CPU 影响和可能更高效的应用程序),它只需要一个循环引用、一个未清除的异常、一个被遗忘的闭包或一个不同的 python 实现要中断,所以你应该真的真的认真考虑你是否想依赖 __del__()
在特定点被调用。
要点3:单例实现通常维护对单例实例的全局引用
根据它的声音,我猜你的单例元类(本身就是一个单例......)在第一次调用 __call__()
时保留了你的单例实例。由于元类属于模块,因此未发布,而模块本身由 sys.modules
保留,因此该引用不会在程序终止时消失,因此即使给出有保证的提示清理对正在释放的单例的所有外部引用,您的 __del__()
将不会被调用。
你可以尝试什么
- 在创建单例实例时添加一个
atexit
处理程序,以便在进程退出时进行必要的整理。 - 如果需要,还可以在
__del__()
方法中进行整理。例如,您可能会决定为了整洁/ future 的可扩展性(例如,使单例复数化),您希望单例实例在不再使用时自行整理。- 如果您实现了一个
__del__()
方法,希望在正常程序执行期间进行整理,您可能还想删除atexit
处理程序。
- 如果您实现了一个
- 如果您希望在没有人使用时清理您的单例,请考虑使用
weakref
将其存储在您的元类中。这样你就不会自己保留它。
关于python - 元类单例对象中的析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35915624/