Python 中的单例对象和复制模块

lin*_*ndy 3 python singleton copy

我定义了这个单例元类:

class Singleton(type):
    """Metaclass which implements the singleton pattern"""

    _instances = {}

    def __call__(self, *args, **kwargs):
        if self not in self._instances:
            self._instances[self] = super(Singleton, self).__call__(*args, **kwargs)
        return self._instances[self]
Run Code Online (Sandbox Code Playgroud)

现在,我想测试是否一切正常。这是我尝试过的:

  • 我创建了同一个类的两个对象(具有Singleton元类的类) - 它们的id()匹配
  • 我创建了一个对象并将其分配给第二个变量 - 它们的id()匹配项
  • 我导入了copy模块并复制了第一个对象copy.copy()- 它们id()现在不匹配

我想知道为什么复制的对象的 id 与原始对象不匹配。既然是单例,那两个对象不应该有相同的id吗?

Mar*_*ers 5

copy模块并不能创建新的实例; 相反,它创建一个空类,并__class__在该对象上重新分配以专门避免原始的__new__or__init__方法。

您需要提供一个自定义__copy__钩子来返回不变的实例:

class Singleton(type):
    """Metaclass which implements the singleton pattern"""

    _instances = {}

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

    def __copy__(cls, instance):
        return instance
Run Code Online (Sandbox Code Playgroud)

copy__copy__直接在类上查找方法;相反,它是在元类上找到的,在类上查找__copy__将返回一个绑定方法,并且copy(期望一个未绑定的方法)显式地传入实例。这意味着将有两个参数传入__copy__; 第一个是类(元类的实例),第二个是该类的实例(self在传统方法中)。

不幸的是,__deepcopy__在实例上查找,并且没有找到元类方法。