22

我必须像这样腌制一组对象:

import cPickle as pickle
from numpy import sin, cos, array
tmp = lambda x: sin(x)+cos(x)
test = array([[tmp,tmp],[tmp,tmp]],dtype=object)
pickle.dump( test, open('test.lambda','w') )

它给出了以下错误:

TypeError: can't pickle function objects

有办法解决吗?

4

3 回答 3

23

内置的 pickle 模块无法序列化多种 python 对象(包括 lambda 函数、嵌套函数和在命令行定义的函数)。

picloud包包含一个更强大的pickler ,它可以pickle lambda 函数。

from pickle import dumps
f = lambda x: x * 5
dumps(f) # error
from cloud.serialization.cloudpickle import dumps
dumps(f) # works

PiCloud 序列化对象可以使用普通的pickle/cPickleloadloads函数进行反序列化。

Dill也提供了类似的功能

>>> import dill           
>>> f = lambda x: x * 5
>>> dill.dumps(f)
'\x80\x02cdill.dill\n_create_function\nq\x00(cdill.dill\n_unmarshal\nq\x01Uec\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x08\x00\x00\x00|\x00\x00d\x01\x00\x14S(\x02\x00\x00\x00Ni\x05\x00\x00\x00(\x00\x00\x00\x00(\x01\x00\x00\x00t\x01\x00\x00\x00x(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00<lambda>\x01\x00\x00\x00s\x00\x00\x00\x00q\x02\x85q\x03Rq\x04c__builtin__\n__main__\nU\x08<lambda>q\x05NN}q\x06tq\x07Rq\x08.'
于 2013-05-18T16:52:48.850 回答
9

您必须改用一个实际的函数,一个可导入的函数(不嵌套在另一个函数中):

import cPickle as pickle
from numpy import sin, cos, array
def tmp(x):
    return sin(x)+cos(x)
test = array([[tmp,tmp],[tmp,tmp]],dtype=object)
pickle.dump( test, open('test.lambda','w') )

函数对象仍然可以由lambda表达式生成,但前提是您随后为生成的函数对象赋予相同的名称:

tmp = lambda x: sin(x)+cos(x)
tmp.__name__ = 'tmp'
test = array([[tmp, tmp], [tmp, tmp]], dtype=object)

因为pickle只存储函数对象的模块和名称;在上面的例子中,tmp.__module__现在tmp.__name__指向在 unpickling 时可以再次找到相同对象的位置。

于 2013-05-18T16:19:57.350 回答
5

还有另一种解决方案:将函数定义为字符串,pickle/un-pickle 然后使用 eval,例如:

import cPickle as pickle
from numpy import sin, cos, array
tmp = "lambda x: sin(x)+cos(x)"
test = array([[tmp,tmp],[tmp,tmp]],dtype=object)
pickle.dump( test, open('test.lambda','w') )
mytmp = array([[eval(x) for x in l] for l in pickle.load(open('test.lambda','r'))])
print mytmp
# yields : [[<function <lambda> at 0x00000000033D4DD8>
#            <function <lambda> at 0x00000000033D4E48>]
#           [<function <lambda> at 0x00000000033D4EB8>
#            <function <lambda> at 0x00000000033D4F28>]]

这对于其他解决方案可能更方便,因为腌制表示将完全自包含,而无需使用外部依赖项。

于 2013-06-29T13:07:25.820 回答