私はこのようなオブジェクトの配列をピクルスにする必要があります:
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
それを回避する方法はありますか?
組み込みのpickleモジュールは、いくつかの種類のpythonオブジェクト(ラムダ関数、ネストされた関数、コマンドラインで定義された関数を含む)をシリアル化できません。
picloud パッケージには、ラムダ関数をピクルスできる、より堅牢なピッカーが含まれています。
from pickle import dumps
f = lambda x: x * 5
dumps(f) # error
from cloud.serialization.cloudpickle import dumps
dumps(f) # works
PiCloudでシリアル化されたオブジェクトは、通常のpickle/cPickle load
およびloads
関数を使用して逆シリアル化できます。
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.'
代わりに、インポート可能な(別の関数内にネストされていない)実際の関数を使用する必要があります。
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__
ピクルスを外すと、同じオブジェクトが再び見つかる場所をすぐに指し示します。
別の解決策があります:関数を文字列として定義し、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>]]
Pickle化された表現は、外部の依存関係を使用せずに完全に自己完結するため、これは他のソリューションにとってより便利な場合があります。