deepcopy不尊重元类

时间:2012-03-27 10:13:03

标签: python singleton metaclass

我有一个类,按照设计,必须遵循 singleton 模式。所以我继续使用元类实现它。一切都运行良好,直到报告了一个错误,总的来说,deepcopy - 我的 singleton 类的实例不是同一个实例。

我可以通过继承基础 singleton 类型来解决这个问题,但我不愿意,因为this question中指出的原因。

此问题的一个工作示例如下:

class SingletonMeta(type):
    def __init__(cls, name, bases, dict):
        super(SingletonMeta, cls).__init__(name, bases, dict)
        cls.instance = None 
    def __call__(cls,*args,**kw):
        print "SingletonMeta __call__ was called"
        if cls.instance is None:
            cls.instance = super(SingletonMeta, cls).__call__(*args, **kw)
        return cls.instance

class MyClass1(object):
    __metaclass__ = SingletonMeta

class SingletonBase(object):
    _instance = None
    def __new__(class_, *args, **kwargs):
        print "SingletonBase __new__ was called"
        if not isinstance(class_._instance, class_):
            class_._instance = object.__new__(class_, *args, **kwargs)
        return class_._instance

class MyClass2(SingletonBase):
  pass

from copy import deepcopy as dcp

mm1 = MyClass1()
mm2 = dcp(mm1)
print "mm1 is mm2:", mm1 is mm2

mb1 = MyClass2()
mb2 = dcp(mb1)
print "mb1 is mb2:", mb1 is mb2

输出:

SingletonMeta __call__ was called
mm1 is mm2: False
SingletonBase __new__ was called
SingletonBase __new__ was called
mb1 is mb2: True

您能否就如何解决此问题向我提出任何建议?我正在运行Python 2.7.X

2 个答案:

答案 0 :(得分:2)

copy模块上的文档说明了这一点:

  

为了让类定义自己的副本实现,它可以定义特殊方法__copy__()__deepcopy__()。   [...]   调用后者来实现深拷贝操作;它传递了一个参数,即备忘录字典。   [...]

因此,如果您声明这些返回self,则应该这样做。

答案 1 :(得分:1)

当您需要自定义类创建时(实例创建),您可以在元类的__new__方法中执行此操作:

def __new__(cls, name, bases, dict):
    dict['__deepcopy__'] = dict['__copy__'] = lambda self, *args: self
    return super(SingletonMeta, cls).__new__(cls, name, bases, dict)

你的测试将给出

SingletonMeta __call__ was called
mm1 is mm2: True

您还需要定义__copy__,甚至浅版也会产生新的实例。

很高兴我在该主题中的解决方案派上了用场。