Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot pickle lambda function in python 3

Using dill pickling of lambda functions work fine in Python 2, but not in Python 3, is there any alternative?

Python 3:

import dill 
import pickle
pickle.dumps(lambda x: x**2)

pickle.PicklingError: Can't pickle at 0x104e97840>: attribute lookup on main failed

Python 2.7:

import dill
import pickle
pickle.dumps(lambda x: x**2)

cdill.dill\n_create_function\np0\n(cdill.dill\n_load_type\np1\n(S'CodeType'\np2\ntp3\nRp4\n(I1\nI1\nI2\nI67\nS'|\x00\x00d\x01\x00\x13S'\np5\n(NI2\ntp6\n(t(S'x'\np7\ntp8\nS''\np9\nS''\np10\nI1\nS''\np11\n(t(ttp12\nRp13\nc__main__\n__dict__\ng10\nNN(dp14\ntp15\nRp16\n.

like image 405
rajat Avatar asked Sep 13 '17 15:09

rajat


People also ask

Can you pickle a lambda function?

Yes, python can pickle lambda functions… but only if you have something that uses copy_reg to register how to pickle lambda functions — the package dill loads the copy_reg you need into the pickle registry for you, when you import dill .

Can you pickle Python functions?

In Python, you can use pickle to serialize (deserialize) an object structure into (from) a byte stream. Here are best practices for secure Python pickling. Pickle in Python is primarily used in serializing and deserializing a Python object structure.

What are the limitations of lambda function in Python?

In Python, lambda functions are quite limited. They can take any number of arguments; however they can contain only one statement and be written on a single line. This will apply the anonymous function lambda x: x * 2 to every item returned by range(10) .

Can Python lambda have multiple lines?

No, you cannot write multiple lines lambda in Python. The lambda functions can have only one expression.


2 Answers

I'm the dill author.

You can use dill in python3 without using dill directly... however, it's not as nice as in python2 just yet.

>>> import dill
>>> import pickle
>>> pickle._dumps(lambda x:x*x)
b'\x80\x03cdill.dill\n_create_function\nq\x00(cdill.dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x01K\x00K\x01K\x02KCC\x08|\x00\x00|\x00\x00\x14Sq\x05N\x85q\x06)X\x01\x00\x00\x00xq\x07\x85q\x08X\x07\x00\x00\x00<stdin>q\tX\x08\x00\x00\x00<lambda>q\nK\x01C\x00q\x0b))tq\x0cRq\rc__main__\n__dict__\nh\nNN}q\x0etq\x0fRq\x10.'

You'll note the _dumps. Maybe you think that's weird. It is. It's because in python3, pickle has been merged with module that used to be called cPickle. Oddly:

  1. import _pickle gives you the old cPickle module
  2. import pickle gives you the pickle module, with cPickle merged in
  3. pickle.dumps is just _pickle.dumps (i.e. it's cPickle)
  4. pickle._dumps is the old pickle.dumps function

Confusing? The crux of it is: pickle.dumps is coded in C. The 2.x version of pickle.dumps was coded in python, but now it's been replaced by what was cPickle.dumps. If you want to get to the "old" version, you can... it's pickle._dumps.

When you import dill, dill automatically registers all objects it knows how to serialize to the the pickle serialization table -- the python one, not the C one. So, in python3, that means the one connected to pickle._dumps.

I suggest using dill.dumps directly instead.

>>> dill.dumps(lambda x:x*x)
b'\x80\x03cdill.dill\n_create_function\nq\x00(cdill.dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x01K\x00K\x01K\x02KCC\x08|\x00\x00|\x00\x00\x14Sq\x05N\x85q\x06)X\x01\x00\x00\x00xq\x07\x85q\x08X\x07\x00\x00\x00<stdin>q\tX\x08\x00\x00\x00<lambda>q\nK\x01C\x00q\x0b))tq\x0cRq\rc__builtin__\n__main__\nh\nNN}q\x0etq\x0fRq\x10.'

I'd like to try to get the C table to work eventually...

like image 74
Mike McKerns Avatar answered Oct 23 '22 07:10

Mike McKerns


Seems like in python 2, dill replaces pickle when you import. In python 3, you have to use dill directly instead.

This works in python 3.5:

>>> import dill 
>>> dill.dumps(lambda x: x**2)
b'\x80\x03cdill.dill\n_create_function\nq\x00(cdill.dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x01K\x00K\x01K\x02KCC\x08|\x00\x00d\x01\x00\x13Sq\x05NK\x02\x86q\x06)X\x01\x00\x00\x00xq\x07\x85q\x08X\x07\x00\x00\x00<stdin>q\tX\x08\x00\x00\x00<lambda>q\nK\x01C\x00q\x0b))tq\x0cRq\rc__builtin__\n__main__\nh\nNN}q\x0etq\x0fRq\x10.'

Alternatively you can also import dill as pickle

>>> import dill as pickle 
>>> pickle.dumps(lambda x: x**2)
like image 35
Håken Lid Avatar answered Oct 23 '22 08:10

Håken Lid