Fyn*_*ney 46 python pickle defaultdict
我有一个看起来像这样的defaultdict:
dict1 = defaultdict(lambda: defaultdict(int))
Run Code Online (Sandbox Code Playgroud)
问题是,我不能用cPickle来腌制它.我在这里找到的解决方案之一是使用模块级函数而不是lambda.我的问题是,什么是模块级功能?如何在cPickle中使用字典?
slo*_*oth 56
除了Martijn的解释:
模块级函数是在模块级定义的函数,这意味着它不是类的实例方法,它不嵌套在另一个函数中,它是一个带有名称而不是lambda函数的"真实"函数.
所以,要腌制你的defaultdict
,用模块级函数而不是lambda函数创建它:
def dd():
return defaultdict(int)
dict1 = defaultdict(dd) # dd is a module-level function
Run Code Online (Sandbox Code Playgroud)
你可以腌它
tmp = pickle.dumps(dict1) # no exception
new = pickle.loads(tmp)
Run Code Online (Sandbox Code Playgroud)
Mar*_*ers 17
Pickle希望存储所有实例属性,而defaultdict
实例存储对default
callable 的引用.Pickle对每个实例属性进行递归.
泡菜不能处理lambdas; pickle只处理数据,而不是代码,lambdas包含代码.可以对函数进行pickle,但只有在可以导入函数时才像类定义一样.可以导入在模块级别定义的函数.在这种情况下,Pickle只存储一个字符串,即要再次进行unpickling时要导入和引用的函数的完整"路径".
jam*_*lak 12
但是,您可以用它partial
来完成此任务:
>>> from collections import defaultdict
>>> from functools import partial
>>> pickle.loads(pickle.dumps(defaultdict(partial(defaultdict, int))))
defaultdict(<functools.partial object at 0x94dd16c>, {})
Run Code Online (Sandbox Code Playgroud)
要做到这一点,只需编写您想要编写的代码.我会使用dill,它可以序列化lambdas和defaultdicts.Dill可以在python中序列化几乎任何东西.
>>> 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>, {})
Run Code Online (Sandbox Code Playgroud)
对于这种情况,解决方案仍然可以作为单行代码,并且实际上比启动的lambda
(或等效的-ed)函数更有效:def
dict1 = defaultdict(defaultdict(int).copy)
Run Code Online (Sandbox Code Playgroud)
这只是创建一个模板defaultdict(int)
,并将其copy
方法绑定为外部的默认工厂defaultdict
。其中的所有内容都是可挑选的,并且在 CPython(其中defaultdict
是用 C 实现的内置类型)上,它比调用任何用户定义的函数来完成相同的工作更有效。不需要额外的进口、包装等。
dict1 = defaultdict(lambda: defaultdict(int))
cPickle.dump(dict(dict1), file_handle)
Run Code Online (Sandbox Code Playgroud)
为我工作