2013-05-18 14 views
19

muszę marynowane tablicę obiektów tak:Python, cPickle, marynowanie funkcje lambda

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')) 

i daje następujący błąd:

TypeError: can't pickle function objects 

Czy istnieje sposób wokół to?

+0

Wydaje się dziwną rzeczą do zrobienia. Jaka jest użyteczność? – Aya

+0

@Aya lambdify w SymPy sprawia, że ​​bardzo wygodne jest tworzenie funkcji lambda. I chcę je ocenić za pomocą Cythona. Możesz [więcej informacji znajdziesz w tym drugim pytaniu] (http://stackoverflow.com/questions/16295140/numerical-integration-over-a-matrix-functions-sympy-and-scipy) –

+1

Cóż, ja don Coś dużo o Cythonie, ale rozwiązanie Martijna zadziała tylko wtedy, gdy Cython zaimportuje plik Pythona, w którym zdefiniowano funkcję 'tmp (x)'. – Aya

Odpowiedz

22

Wbudowany moduł pikle nie jest w stanie szeregować szeregów różnych typów obiektów python (w tym funkcji lambda, funkcji zagnieżdżonych i funkcji zdefiniowanych w wierszu poleceń).

Pakiet picloud zawiera bardziej odporny odbiornik, który może korzystać z funkcji lambda.

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

PiCloud-serializowane obiekty mogą być oddzielone od odcinkach za pomocą normalnego ogórka/cPickle load i loads funkcji.

Dill zapewnia również podobną funkcjonalność

>>> 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.' 
+0

dziękuję! z pakietem picloud to działało! The Dill, którego jeszcze nie testowałem ... Utworzony pikla można załadować za pomocą konwencjonalnych modułów pickle lub cPickle. –

+1

Czy istnieje sposób wykorzystania tego pickera w bibliotece wieloprocesowej? –

+0

Odpowiedź brzmi: rodzaj http://stackoverflow.com/questions/19984152/what-can-multiprocessing-and-dill-do-together –

9

Będziesz musiał użyć zamiast rzeczywistej funkcji, który jest importable (nie zagnieżdżony wewnątrz innej funkcji):

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')) 

Przedmiotem funkcja może być nadal produkowane przez ekspresję lambda, ale tylko wtedy, gdy następnie daje wynikowy funkcyjnych samą nazwę: tylko

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

Ze względu pickle przechowuje moduł i nazwę obiektu funkcyjną; w powyższym przykładzie, tmp.__module__ i tmp.__name__ wskazują teraz ponownie miejsce, w którym ten sam obiekt można znaleźć ponownie, gdy zostanie on rozpakowany.

+0

Domyślam się, że tego rodzaju odpowiedzi nie można używać na wbudowanych funkcjach modułów opartych na C * (nawet jeśli ᴏꜱ i architektura pozostają takie same) *. – user2284570

+0

@ user2284570: pickle ma określone funkcje do przechowywania odniesień do struktur C. Jednak, aby "podnieść" funkcję, wszystko, co jest przechowywane, jest zbiorem ciągów znaków (moduł plus nazwa w module), które są dereferencjonowane po ponownym rozpakowaniu. –

+0

Czy masz na myśli możliwość zapisania, ale nie przywrócenia pliku wykonywalnego? Interesuje mnie tylko przywracanie * (tworzenie zrzutu nie musi odbywać się w pythonie) *. Nie obchodzi mnie, co jest używane * (marszałek lub cPickle) * o ile żadne moduły stron trzecich nie są używane z uruchomieniem numpy. – user2284570

5

istnieje inne rozwiązanie: define ci funkcje jak struny, ogórka/un-opa następnie użyć eval, ex:

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>]] 

to może być wygodniejsze dla innych rozwiązań, ponieważ wytrawiona reprezentacja byłaby całkowicie autonomiczna bez konieczności korzystania z zewnętrznych zależności.

Powiązane problemy