2013-05-08 82 views
34

我有一個defaultdict,看起來像這樣:不能鹹菜defaultdict

dict1 = defaultdict(lambda: defaultdict(int)) 

的問題是,我可以不使用cPickle的鹹菜吧。我在這裏找到的解決方案之一是使用模塊級功能而不是lambda。我的問題是,什麼是模塊級功能?我怎樣才能用cPickle使用字典?

回答

40

除了Martijn's explanation

模塊級的功能是其在模塊級上定義的函數,這意味着它不是一個一個類的實例方法,它不嵌套在另一個函數中,它是一個帶有名稱而不是lambda函數的「真實」函數。

所以,醃您defaultdict,與模塊級的功能,而不是lambda函數創建它:

def dd(): 
    return defaultdict(int) 

dict1 = defaultdict(dd) # dd is a module-level function 

比你可以泡製它

tmp = pickle.dumps(dict1) # no exception 
new = pickle.loads(tmp) 
11

Pickle希望存儲所有實例屬性,並且defaultdict實例存儲對default可調用的引用。 Pickle在每個實例屬性上遞歸。

泡椒不能處理羊肉; pickle只處理數據,而不是代碼,而lambda包含代碼。功能可以被酸洗,但只是類的定義只有當功能可以是進口。可以導入在模塊級定義的功能。 Pickle只是在這種情況下存儲一個字符串,這個函數的完整'路徑'被導入並在再次取消時被引用。

7

然而可以使用partial來實現:

>>> from collections import defaultdict 
>>> from functools import partial 
>>> pickle.loads(pickle.dumps(defaultdict(partial(defaultdict, int)))) 
defaultdict(<functools.partial object at 0x94dd16c>, {}) 
+1

您能爲我解壓這是如何工作的嗎?我很感興趣...... – Fred 2013-10-15 18:00:58

1

目前我在做類似的東西但是,對poser問題,我使用了defaultdict的子類,它具有用作default_factory的成員函數。爲了使我的代碼正常工作(我需要在運行時定義函數),我只是添加了一些代碼來準備酸洗對象。

相反的:

... 
pickle.dump(dict, file) 
... 

我用這個:

.... 
factory = dict.default_factory 
dict.default_factory = None 
pickle.dump(dict, file) 
dict.default_factory = factory 
... 

這不是我作爲我的樹確切的代碼是創建相同的樹的類型的實例對象索引被請求(所以我使用遞歸成員函數來執行pickle操作之前/之後的操作),但是這種模式也回答了這個問題。

+0

請注意,如果你不在意丟失pickled字典的'default_factory',那麼這樣做是很好的。如果你不再需要工廠,你可以簡單地將它設置爲None(無)並完成(: – drevicko 2014-09-19 03:41:45

5

要做到這一點,只需編寫你想寫的代碼即可。我會使用dill,它可以序列化lambdas和defaultdicts。蒔蘿可以序列化幾乎任何蟒蛇。

>>> import dill 
>>> from collections import defaultdict 
>>> 
>>> dict1 = defaultdict(lambda: defaultdict(int)) 
>>> pdict1 = dill.dumps(dict1) 
>>> _dict1 = dill.loads(pdict1) 
>>> _dict1 
defaultdict(<function <lambda> at 0x10b31b398>, {}) 
+0

這很好。有沒有辦法將dict1轉儲到臨時文件中,然後重新加載它?類似的東西對於從文件中寫入和讀取的pickle操作來說.. – 2014-09-07 06:15:03

+0

當然''dill'提供了通常的'dump'和'load',可以像'pickle'中的'dump'和'load'一樣使用。想要查看'dill.temp.dump'這個轉儲到'NamedTemporaryFile'。 – 2014-09-07 12:33:34

+0

謝謝,看看我的個人資料上的最新問題,你可以在那裏發佈你的答案。 – 2014-09-07 14:21:50

1

如果你不關心保留defaultdict類型,將其轉換:

​​

我認爲這是當你是酸洗,因爲一個偉大的選擇,對象很可能是在它的最終形式...並且,如果真的需要再次使用defaultdict類型,則可以在解開後簡單地進行轉換:

for value in my_dict: 
    my_dict[value] = defaultdict(type, my_dict[value]) 
nested_default_dict = defaultdict(type, my_dict)