理解 Python 中的 Borg 单例模式

San*_*osh 6 python oop design-patterns class

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

这是单例代码

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
Run Code Online (Sandbox Code Playgroud)

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

Ash*_*ary 5

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

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

在您的情况下,每次创建实例时,您都会将其字典分配为指向Borg. _shared_state. 因此,它的所有实例将使用相同的字典来获取和设置属性。

它基本上相当于:

shared = {}

class A(object):
    def __init__(self):
        self.__dict__ = shared
Run Code Online (Sandbox Code Playgroud)

演示:

>>> 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}
Run Code Online (Sandbox Code Playgroud)

在 CPython 中,新字典的分配__dict__发生在内部PyObject_GenericSetDict

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;
}
Run Code Online (Sandbox Code Playgroud)

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