不能pickle defaultdict

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实例存储对defaultcallable 的引用.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)


Mik*_*rns 7

要做到这一点,只需编写您想要编写的代码.我会使用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)


Sha*_*ger 7

对于这种情况,解决方案仍然可以作为单行代码,并且实际上比启动的lambda(或等效的-ed)函数更有效:def

dict1 = defaultdict(defaultdict(int).copy)
Run Code Online (Sandbox Code Playgroud)

这只是创建一个模板defaultdict(int),并将其copy方法绑定为外部的默认工厂defaultdict。其中的所有内容都是可挑选的,并且在 CPython(其中defaultdict是用 C 实现的内置类型)上,它比调用任何用户定义的函数来完成相同的工作更有效。不需要额外的进口、包装等。


Avi*_*Avi 5

dict1 = defaultdict(lambda: defaultdict(int))
cPickle.dump(dict(dict1), file_handle)
Run Code Online (Sandbox Code Playgroud)

为我工作