理解Python中的Borg单例模式

理解Python中的Borg单例模式,python,class,oop,design-patterns,Python,Class,Oop,Design Patterns,我看到了这个Borg Singleton模式代码,但我无法理解我添加到Singleton对象的新成员是如何附加到\uuuuuShared\uState={}字典中的 这是单例代码 class Borg(object): _shared_state = {} def __new__(cls,*args,**kwargs): obj = super(Borg,cls).__new__(cls,*args,**kwargs) obj.__dict__

我看到了这个Borg Singleton模式代码,但我无法理解我添加到Singleton对象的新成员是如何附加到
\uuuuuShared\uState={}
字典中的

这是单例代码

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
被创建时,它是如何被附加到
\u shared_state
字典的?在一个类外上下文字典的简单情况下,您可能知道,您可以附加新的键值对,如:

dic = {}
dic['first'] = 1
print(dic)
>>> {'first': 1}
在您的例子中,您将
\u共享\u状态
字典分配给对象的字典
obj.\uu dict\uu
。所以现在,
obj.\uuuuu dict\uuuuuu
是对
\u共享\u状态
字典的引用

当您在
obj
实例上使用该点路径表示法时,实际上会将一个键值对附加到它的字典中,从而附加到
\u共享\u状态
字典中


因为这个类是一个单例,所以所有其他实例的字典将引用相同的
\u共享\u状态
字典。因此,默认情况下,所有实例都将具有“相同的”
\uuuu dict\uuuu

,因此,为一个实例分配属性不会影响其他实例

但您可以使实例的字典指向一个新的dict,当您在内部这样做时,它将从此处开始用于存储项

在您的例子中,每次创建实例时,您都将其字典分配给指向
Borg的对象_共享状态
。因此,它的所有实例都将使用相同的dict来获取和设置属性

这基本上相当于:

shared = {}

class A(object):
    def __init__(self):
        self.__dict__ = shared
演示:

>>> 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}
在CPython中,将新词典分配给
\uuuu dict\uuu
发生在:



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

不起作用<代码>类型错误:无法设置内置/扩展类型“dict”的属性。谢谢。写字典和思考对象。愚蠢的我:)
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;
}