2013-05-18 7 views
19

Ich habe ein Array von Objekten wie diese beizen:Python, cPickle, Beizen Lambda-Funktionen

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

und es gibt die folgenden Fehler:

TypeError: can't pickle function objects 

Gibt es eine Möglichkeit, um das?

+0

Scheint wie eine seltsame Sache zu tun. Was ist der Anwendungsfall? – Aya

+0

@Aya Lambdify in SymPy macht es sehr bequem, Lambda-Funktionen zu erstellen. Und ich möchte sie mit Cython auswerten. Sie können [auf diese andere Frage für weitere Informationen verweisen] (http://stackoverflow.com/questions/16295140/numerical-integration-over-a-matrix-of-functions-sympy-and-scipy) –

+1

Nun, ich don Ich weiß nicht viel über Cython, aber Martijns Lösung wird nur funktionieren, wenn es für Cython möglich ist, die Python-Datei zu importieren, in der die Funktion 'tmp (x)' definiert wurde. – Aya

Antwort

22

Das integrierte Beizmodul kann mehrere Arten von Python-Objekten (einschließlich Lambda-Funktionen, verschachtelte Funktionen und Funktionen, die in der Befehlszeile definiert sind) nicht serialisieren.

Das Paket picloud enthält einen robusteren Picker, der Lambda-Funktionen beizen kann.

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

PiCloud-serialisierte Objekte können deserialisiert die normale Gurke mit/cPickle load und loads Funktionen.

Dill bietet auch eine ähnliche Funktionalität

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

danke! mit Picloud-Paket hat es funktioniert! Den Dill habe ich noch nicht getestet ... Die erstellte Beize kann mit den herkömmlichen Pickle- oder cPickle-Modulen geladen werden –

+1

Gibt es eine Möglichkeit, diesen Picker mit der Multiprocessing-Bibliothek zu verwenden? –

+0

Die Antwort ist: Art von http://stackoverflow.com/questions/19984152/what-can-multiprocessing-and-dill-do-together –

9

Sie werden eine eigentliche Funktion verwenden, anstatt eine, die importierbar ist (nicht in einer anderen Funktion verschachtelt):

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

Die Funktion Objekt noch durch einen lambda Ausdruck erzeugt werden könnte, aber wenn man nur anschließend geben die sich ergebenden Funktionsobjekt denselben Namen:

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

weil pickle speichert nur das Modul und einen Namen für ein Funktionsobjekt; Im obigen Beispiel zeigen tmp.__module__ und tmp.__name__ jetzt direkt auf die Stelle zurück, an der das gleiche Objekt beim Entpacken wieder gefunden wird.

+0

Ich denke, diese Art von Antwort kann nicht auf integrierten Funktionen von C-basierten Modulen * verwendet werden (auch wenn ᴏꜱ und Architektur gleich bleiben) *. – user2284570

+0

@ user2284570: pickle verfügt über spezifische Funktionen zum Speichern von Verweisen auf C-Strukturen. Um jedoch eine Funktion zu "säubern", ist alles, was gespeichert wird, eine Menge von Strings (Modul plus Name innerhalb des Moduls), die beim erneuten Entkoppeln dereferenziert werden. –

+0

Also meinst du es ist möglich, etwas ausführbares zu speichern, aber nicht wiederherzustellen? Ich bin nur daran interessiert, * wiederherzustellen (das Erstellen des Dumps muss nicht in Python erfolgen) *. Es ist mir egal, was verwendet wird * (Marshal oder cPickle) * solange keine Module von Drittanbietern mit der Ausnahme von numpy verwendet werden. – user2284570

5

Es gibt eine andere Lösung: Sie definieren Funktionen als Strings, Gurke/un-Beize dann eval verwenden, 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>]] 

Diese bequemer sein könnte für andere Lösungen, da die in Essig eingelegte Darstellung vollständig unabhängig wäre, ohne externe Abhängigkeiten verwenden zu müssen.