我有一个类,按照设计,必须遵循 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
答案 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__
,甚至浅版也会产生新的实例。
很高兴我在该主题中的解决方案派上了用场。