Pickling wrapped partial functions

故事扮演 提交于 2019-11-30 04:54:54

问题


I am trying to create a picklable decorator using partial functions. However, I keep getting pickling errors when trying to do that.

The first naïve example is as follows:

def decorator(func):
  def wrapper(**kwargs):
    return partial(func, **kwargs)
  return wrapper

@decorator
def decorated(x, y=1, z=2):
  return x+y+z

y5 = decorated(y=5)
pickle.dumps(y5)

Where partial is taken from functools.

A bit less naïve attempt involves adding @wraps one line above def wrapper. This doesn't help.

I'm not sure I understand how pickling really works.


回答1:


The problem is in your decorator, not with partial. A partial object should pickle just fine:

>>> from pickle import *
>>> from functools import *
>>> f = partial(pow, 2)
>>> p = dumps(f)
>>> g = loads(p)
>>> g(5)
32

So, this issue with your code is in the decorator. It is not preserving the name of the original function. Try this instead:

import pickle
from functools import *

def decorator(func):
    def wrapper(**kwargs):
        return partial(func, **kwargs)
    return wrapper

def decorated(x, y=1, z=2):
    return x+y+z

dd = decorator(decorated)

y5 = dd(y=5)
pickle.dumps(y5)

The modification to use dd should allow the pickle logic to discover the underlying function by its name. That is how pickles work.

To see the function name in the pickle, look at the dumps output:

>>> print pickle.dumps(y5)
cfunctools
partial
p0
(c__main__
decorated
p1
tp2
Rp3
(g1
(t(dp4
S'y'
p5
I5
sNtp6
b.

The word "decorated" needs to be findable, equal to the underlying function, and not be hidden by the decorator. Remember, when functions get pickled, only their names get stored. The actual contents of the function aren't in the pickle.

There are some workarounds, but they aren't pretty. You can use __setstate__() to save both the function name and its source-code. Then add a __getstate__() method to restore the function by exec-ing its source.

Alternatively, you can extract the byte codes in the function object object and save those. Upon a restore, compile the code object and exec it.

In short, your goal of using a decorator with the @ notation is directly at odds with how function pickling works. In order to achieve your goal, you'll have to customize function pickling to have it save what the function does, not just its name.



来源:https://stackoverflow.com/questions/14550577/pickling-wrapped-partial-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!