【问题标题】:Destroying a Singleton object in Python在 Python 中销毁单例对象
【发布时间】:2017-04-25 19:51:18
【问题描述】:

我在 Python 中有一个 Singleton 对象:

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

我想在某个时候销毁对象,所以我在元类中编写了一个类方法。但是,cls 指的是元类Singleton 而不是MockObject。有没有办法以MockObject 的值调用destroy 函数?

【问题讨论】:

  • destroy 方法放在它所属的MockObject 上(或创建一个MockBase 来执行此操作)。但是无论如何尝试销毁实例是没有意义的。如果在任何地方有任何其他对它的引用,它将保持活动状态。
  • 为什么不在元类上定义一个__del__ 方法?
  • 正如@kindall 指出的那样,您实际上会通过这样做引入一大堆污染。您将删除字典中的引用,但不会删除程序在其他地方的任何挥之不去的引用。现在,您最终会得到多个漂浮的单例实例。您可能想了解如何在 Python 中真正删除对象并重新考虑您的方法。
  • 可能是del Singleton._instances[cls]。您还可以使用gc 模块来确保只有一个引用,否则会引发错误。
  • 另外,您是否考虑过一种更简单的方法,您只需在元类上重新定义__new__ 而不是__call__,它应该同时调用__new____init__?这基本上就是 boolNoneType 在 Python 中所做的。

标签: python python-3.x metaprogramming


【解决方案1】:

不要定义删除实例引用的自定义方法,而是使用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>}
{}

【讨论】:

    猜你喜欢
    • 2011-04-16
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多