According to the documentation, this code seems like it should pickle various elements of a function and allow it to be unpickled, even if it did not exist in the current namespace. However, no change appears.
Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def average(*args):
... return sum(args) / len(args)
...
>>> import pickle
>>> ap = pickle.dumps(average)
>>> del average
>>> average = pickle.loads(ap)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'average'
>>> ap
b'\x80\x03c__main__\naverage\nq\x00.'
>>>
As you can see, it is impossible to unpickle a function that does not exist. Security issues aside, the following code was expected to fix the problem and allow functions to be pickled and unpickled.
>>> import marshal, types, copyreg
>>> copyreg.pickle(types.CodeType,
... lambda code: (marshal.loads, (marshal.dumps(code),)),
... marshal.loads)
...
>>> up = lambda co, ns, de, cl: types.FunctionType(co, globals(), na, de, cl)
>>> copyreg.pickle(types.FunctionType,
... lambda function: (up, (function.__code__,
... function.__name__,
... function.__defaults__,
... function.__closure__)),
... up)
...
>>> def average(*args):
... return sum(args) / len(args)
...
>>> pickle.dumps(average)
b'\x80\x03c__main__\naverage\nq\x00.'
>>>
One would expect that if the code were working properly, the bytes emitted by dumping the function would be different than before. The same code was generated, and unpickling should be similar.
>>> del average; average = pickle.loads(_)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'average'
>>>
It was easy enough to confirm that theory. Therefore, the question still remains on how to pickle a function natively with the API instead of wrapping it another layer. That is an easy but sloppy solution.
Question: How can you use the pickle
API to have it capture a function and not just its name? How can the default handling for serializing functions be overridden, capturing value instead of reference?
Reference: Question 1253528 was interesting but does not alter how functions are natively pickled.