2017-07-25 30 views
3

我看到了這個Borg Singleton模式代碼,但是我無法理解我如何將新成員添加到單例對象的附加到__shared_state = {}字典中。瞭解Python中的Borg 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字典

回答

3

默認情況下,每個實例都獲取自己的字典,因此將屬性分配給一個實例不會影響其他實例。

但是你可以讓一個實例的字典指向一個新的字典,當你在內部這樣做時,它將被用來存儲物品。

在你的情況下,每創建一個實例,你都要指定它的字典來指向Borg. _shared_state。因此,它的所有實例都將使用相同的字典來獲取和設置屬性。

這基本上等同於:

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的新字典來__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; 
} 

請注意,自從Python 3.3以上的key-sharing dictionaries到來以後,相同類的實例字典可以共享一些內部狀態以節省空間。

1

在淘汰類語境詞典的簡單的情況下,我的問題你可能知道,你可以將新的鍵值對,如:

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

在你的情況,你分配_shared_state該詞典的對象字典obj.__dict__。所以現在的obj.__dict__是對那個_shared_state字典的一個參考。

當您在obj實例上使用該點路徑表示法時,實際上將一個鍵值對添加到其字典中,並因此添加到_shared_state字典中。

由於這個類是一個單例,所有其他實例的字典都會引用同一個_shared_state字典。因此所有的實例將具有「相同」__dict__

+1

不起作用。 'TypeError:不能設置內置/擴展類型的屬性'dict'' – ppperry

+0

謝謝。寫字典和思考物體。傻我:) – nutmeg64