2013-05-18 4 views
19

я должен мариновать массив объектов, как это:Python, cPickle, травление лямбда-функции

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 

Есть ли способ обойти это?

+0

Кажется, это странная вещь. Что такое прецедент? – Aya

+0

@Aya lambdify в SymPy очень удобно создавать лямбда-функции. И я хочу оценить их с помощью Cython. Вы можете [ссылаться на этот другой вопрос для получения дополнительной информации] (http://stackoverflow.com/questions/16295140/numerical-integration-over-a-matrix-of-functions-sympy-and-scipy) –

+1

Ну, я дон не знаю много о Cython, но решение Martijn будет работать, только если Cython может импортировать файл Python, в котором определена функция 'tmp (x)'. – Aya

ответ

22

Встроенный модуль рассола не может сериализовать несколько видов объектов python (включая функции лямбда, вложенные функции и функции, определенные в командной строке).

В комплект поставки picloud входит более прочный раскройщик, который может разводить лямбда-функции.

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

PiCloud-сериализованные объекты могут быть десериализовать используя обычный рассол/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.' 
+0

спасибо! с пакетом picloud это сработало! Dill я еще не тестировал ... Созданный рассол может быть загружен с использованием обычных рассолов или модулей cPickle –

+1

Есть ли способ использовать этот сортировщик с многопроцессорной библиотекой? –

+0

Ответ: вид http://stackoverflow.com/questions/19984152/what-can-multiprocessing-and-dill-do-together –

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__ теперь вернитесь назад в том месте, где тот же самый объект может быть найден снова при рассыпании.

+0

Я предполагаю, что такой ответ не может быть использован для встроенных функций модулей на основе C * (даже если ᴏꜱ и архитектура остаются неизменными) *. – user2284570

+0

@ user2284570: pickle имеет специальные возможности для хранения ссылок на структуры C. Однако, чтобы «раскрыть» функцию, все, что хранится, представляет собой набор строк (модуль плюс имя в модуле), которые разыменовываются при повторной загрузке. –

+0

Итак, вы имеете в виду, что можно сохранить, но не восстановить что-то исполняемое? Меня интересует только восстановление * (создание дампа не должно выполняться в python) *. Меня не волнует, что используется * (маршал или cPickle) * до тех пор, пока никакие сторонние модули не используются с отменой numpy. – user2284570

5

Там есть другое решение: определить вам функции как строки, рассол/ун-рассол затем использовать 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>]] 

Это может быть более удобным для других решений, потому что маринованное представление было бы полностью автономным без использования внешних зависимостей.

Смежные вопросы