2012-03-28 68 views
0

假設我有一個叫做符號的類。在任何時候,我只需要一個帶給定ID的Symbol的副本。例如醃製「實習」對象

registry = {} 

class Symbol(object): 
    def __init__(self, id): 
     self.id = id 
    def __eq__(self, other): 
     return self is other 

def symbol(id): 
    if id not in registry: 
     registry[id] = Symbol(id) 

    return registry[id] 

我希望能夠鹹菜我的符號對象,但我想不出如何讓cPickle的叫我的符號工廠。現在我只能實現getstate/setstate覆蓋,但是這仍然不能將未被識別的對象與已經存在於註冊表中的對象合併。如何在保留1:1比例的符號與ID的同時醃製上述類?


編輯(更新標題狀態「實習」,而不是「單身」):

讓我解釋一下使用情況。我們使用這些符號作爲字符中的鍵。讓他們大幅拘禁提高性能

我需要什麼有發生:

x = symbol("x") 

y = pickle.loads(pickle.dumps(x)) 

x is y == True 
+2

只要不使用單身? – delnan 2012-03-28 14:19:41

+0

那麼,在我的實際案例中,Symbol可以有多個額外的元數據字段,基於「x is y」的比較將比「x.foo == y.foo和x.bar == y」更快。酒吧和...「 – 2012-03-28 14:37:14

+1

pickle不會調用'__init__',但它會調用'__new__'。 – georg 2012-03-28 14:56:37

回答

3

由於您不想使用給定ID的多個對象,請提供自定義__new__方法來代替您的symbol函數。

class Symbol(object): 
    registry = {} 
    def __new__(cls, *args, **kwargs): 
     id_ = args[0] 
     return Symbol.registry.setdefault(_id, object.__new__(cls, *args, **kwargs)) 

    def __init__(self, id): 
     self.id = id 

現在您不需要工廠功能來創建Symbol對象。

$ a = Symbol('=') 
$ b = Symbol('=') 
$ a is b 
True 
0

你可以嘗試這樣子pickle.Unpickler並在load方法實現您的加載邏輯。

但是,您需要某種密鑰才能知道對象是否已在運行時存在(要返回引用而不是新實例)。這將導致您重新實現python對象空間。

我會推薦試圖找到更適合您的實際問題的另一個數據結構。

0

您可能需要使用weakrefWeakValueDictionary爲符號的註冊表,所以當符號不再被引用的垃圾收集可以回收內存。

你可以使用下面的類來定義一個被攔截的對象是什麼。您的Symbol類(或任何其他類)可以從它繼承。

class Interned (object): 
    # you need to create this registry in each class if the keys are not unique system-wide 
    registry = weakref.WeakValueDictionary() 
    def __new__(cls, *args, **kwargs): 
     assert 0 < len(args) 
     if not args[0] in cls.registry: # don't use setdefault to avoid creating unnecessary objects 
      o = object.__new__(cls, *args, **kwargs) # o is a ref needed to avoid garbage collection within this call 
      cls.registry[args[0]] = o 
      return o 
     return cls.registry[args[0]] 
    def __eq__(self, other): 
     return self is other 
    def __hash__(self): 
     # needed by python 3 
     return id(self) 
    def __ne__(self, other): 
     return not self is other 

您的代碼就變成了:

class Symbol(Interned): 
    def __init__(self, id): 
     self.id = id 

結果造成:

$ a = Symbol('=') 
$ b = Symbol('=') 
$ a is b 
True