在Python中销毁单例对象

12

我有一个 Python 中的单例对象:

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

    @classmethod
    def destroy(cls):
        del cls._instances[cls]


class MockObject(metaclass=Singleton):

    def __init__(self, *args, **kwargs):
        # various things

我希望在某个时间点销毁对象,因此我在元类中编写了一个classmethod。然而,cls指的是元类Singleton而不是MockObject。有没有办法以MockObject的值调用destroy函数?


2
destroy 方法放在 MockObject 上,因为它属于它(或者创建一个名为 MockBase 的类来实现这个方法)。但是,如果该实例在其他地方有任何引用,试图销毁它也没有意义,因为它仍然会存在。 - kindall
1
正如@kindall所指出的那样,通过这样做,您实际上将引入大量污染。您将删除字典中的引用,但不会删除程序在其他地方可能存在的任何残留引用。现在,您将得到多个单例实例。您可能需要阅读有关Python中对象实际上是如何被删除的,并重新考虑您的方法。 - Mad Physicist
3
可能会有类似于 del Singleton._instances[cls] 这样的语句。你也可以使用 gc 模块来确保只有一个引用,否则抛出错误。 - kindall
@MadPhysicist 就像我说的,此时此刻已经没有关于这个对象的引用了。我只是想强制删除这些信息,以便稍后可以创建另一个全新的对象。 - user1742188
1
另外,您是否考虑过一种更简单的方法,即仅在元类上重新定义__new__而不是__call__,这应该调用__new____init__两者?这基本上就是Python中boolNoneType所做的。 - Mad Physicist
显示剩余4条评论
1个回答

25

不要定义自定义方法以删除实例引用,而是使用WeakValueDictionary

现在当没有任何对MockObject的引用时,它将自动从Singleton._instances中清除。

from weakref import WeakValueDictionary


class Singleton(type):
    _instances = WeakValueDictionary()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            # This variable declaration is required to force a
            # strong reference on the instance.
            instance = super(Singleton, cls).__call__(*args, **kwargs)
            cls._instances[cls] = instance
        return cls._instances[cls]


class MockObject(metaclass=Singleton):

    def __init__(self, *args, **kwargs):
        pass


if __name__ == '__main__':
    m = MockObject()
    print(dict(Singleton._instances))
    del m
    print(dict(Singleton._instances))

输出:

{<class '__main__.MockObject'>: <__main__.MockObject object at 0x104531128>}
{}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接