在Python中理解Borg Singleton模式

时间:2017-07-25 20:12:00

标签: python class oop design-patterns

我看到了这个Borg Singleton Pattern代码,但我无法理解我添加到singleton对象的新成员是如何附加到__shared_state = {}字典的。

这是Singleton代码

class Borg(object):
    _shared_state = {}

    def __new__(cls,*args,**kwargs):
        obj = super(Borg,cls).__new__(cls,*args,**kwargs)
        obj.__dict__ = cls._shared_state
        return obj

class Child(Borg):
    pass

if __name__ == '__main__':
    borg = Borg()
    another_borg = Borg()

    print borg is another_borg
    child = Child()

    borg.only_one_var = "I'm the only one var"    
    print child.only_one_var

所以当创建对象borg.only_one_var时我的问题是如何将它附加到_shared_state字典

2 个答案:

答案 0 :(得分:3)

默认情况下,每个实例都有自己的字典,因此为一个实例分配属性不会影响其他实例。

但是你可以让一个实例的字典指向一个新的字典,当你在内部这样做时,它将从那里用来存储项目。

在您的情况下,每次创建实例时,您都要将其字典指定为shared = {} class A(object): def __init__(self): self.__dict__ = shared 。因此,它的所有实例都将使用相同的dict来获取和设置属性。

它基本上相当于:

>>> ins = [A() for _ in range(5)]
>>> ins[0].x = 100
>>> for i in ins:
...     print(i.x)
...
100
100
100
100
100

>>> shared
{'x': 100}

<强>演示:

__dict__

在CPython中,新int PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context) { PyObject **dictptr = _PyObject_GetDictPtr(obj); ... if (!PyDict_Check(value)) { PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, " "not a '%.200s'", Py_TYPE(value)->tp_name); return -1; } Py_INCREF(value); Py_XSETREF(*dictptr, value); # Set the dict to point to new dict return 0; } 字典的分配发生在PyObject_GenericSetDict内:

http://

请注意,由于{3}}在Python 3.3+中的到来,同一类实例的字典可以共享一些内部状态以节省空间。

答案 1 :(得分:1)

在一个类外的上下文字典的简单情况下,您可能知道,您可以附加新的键值对,如:

dic = {}
dic['first'] = 1
print(dic)
>>> {'first': 1}

在您的情况下,您将_shared_state字典分配给对象的字典obj.__dict__。所以现在obj.__dict__是对_shared_state词典的引用。

当您在obj实例上使用该点路径表示法时,您实际上将键值对附加到它的词典中,并因此附加到_shared_state词典。

由于这个类是单例,所有其他实例都是&#39;字典将引用相同的_shared_state字典。因此,所有实例都将具有相同的&#34; __dict__