2013-05-18 41 views
19

tôi phải dưa một mảng của các đối tượng như thế này:Python, cPickle, tẩy các hàm 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')) 

và nó mang lại cho các lỗi sau:

TypeError: can't pickle function objects 

Có cách nào xung quanh đó?

+0

Có vẻ như một điều kỳ lạ để làm. Trường hợp sử dụng là gì? – Aya

+0

@Aya lambdify trong SymPy làm cho nó rất thuận tiện để tạo ra các hàm lambda. Và tôi muốn đánh giá chúng bằng cách sử dụng Cython. Bạn có thể [tham khảo câu hỏi khác này để biết thêm thông tin] (http://stackoverflow.com/questions/16295140/numerical-integration-over-a-matrix-of-functions-sympy-and-scipy) –

+1

Vâng, tôi không Không biết nhiều về Cython, nhưng giải pháp của Martijn sẽ chỉ hoạt động nếu Cython có thể nhập tệp Python trong đó hàm 'tmp (x)' đã được xác định. – Aya

Trả lời

22

Mô-đun dưa tích hợp không thể tuần tự hóa một số loại đối tượng python (bao gồm hàm lambda, hàm lồng nhau và hàm được xác định tại dòng lệnh).

Gói picloud bao gồm bộ chọn mạnh mẽ hơn, có thể chọn chức năng lambda.

đối tượng
from pickle import dumps 
f = lambda x: x * 5 
dumps(f) # error 
from cloud.serialization.cloudpickle import dumps 
dumps(f) # works 

PiCloud-serialized có thể được de-đăng bằng cách sử dụng dưa bình thường/cPickle loadloads chức năng.

Dill cũng cung cấp chức năng tương 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

cảm ơn bạn! với gói picloud nó đã hoạt động! Các Dill tôi đã không kiểm tra được nêu ra ... Các dưa chua tạo ra có thể được nạp bằng cách sử dụng pickle thông thường hoặc các mô-đun cPickle –

+1

Có cách nào để sử dụng bộ chọn này với thư viện đa xử lý? –

+0

Câu trả lời là: sắp xếp http://stackoverflow.com/questions/19984152/what-can-multiprocessing-and-dill-do-together –

9

Bạn sẽ phải sử dụng một chức năng thực tế thay vào đó, một trong đó là có thể nhập cảng (không lồng vào bên trong chức năng khác):

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

Đối tượng chức năng vẫn có thể được sản xuất bởi một biểu thức lambda, nhưng chỉ khi bạn sau đó cung cấp cho các kết quả chức năng đối tượng cùng tên:

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

pickle cửa hàng chỉ module và tên cho một đối tượng hàm; trong ví dụ trên, tmp.__module__tmp.__name__ bây giờ trở lại điểm ngay tại vị trí có thể tìm thấy cùng một đối tượng đó khi tháo bỏ.

+0

Tôi đoán rằng loại câu trả lời không thể được sử dụng trên các hàm dựng sẵn của các mô-đun dựa trên C * (ngay cả khi the và kiến ​​trúc vẫn giữ nguyên) *. – user2284570

+0

@ user2284570: dưa có các phương tiện cụ thể để lưu trữ tham chiếu đến cấu trúc C. Tuy nhiên, để 'pickle' một chức năng, tất cả những gì được lưu trữ là một tập hợp các chuỗi (module cộng với tên trong mô-đun) được dereferenced khi unpickling một lần nữa. –

+0

Vì vậy, bạn có nghĩa là nó có thể tiết kiệm nhưng không phải để khôi phục lại một cái gì đó thực thi? Tôi chỉ quan tâm đến việc khôi phục lại * (việc tạo kết xuất không cần phải thực hiện trong python) *. Tôi không quan tâm những gì được sử dụng * (marshal hoặc cPickle) * miễn là không có mô-đun bên thứ ba được sử dụng với sự lừa đảo của numpy. – user2284570

5

Có một giải pháp khác: xác định bạn có chức năng như chuỗi, dưa/un-dưa sau đó sử dụng eval, ví dụ:

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

Điều này có thể thuận tiện hơn cho các giải pháp khác vì biểu diễn muối sẽ hoàn toàn tự chứa mà không phải sử dụng các phụ thuộc bên ngoài.