酸洗装饰可调用类包装器 [英] Pickling decorated callable class wrapper

查看:135
本文介绍了酸洗装饰可调用类包装器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用自定义的可调用类作为包装器时,我正在努力使包装的函数腌制.

I'm struggling to pickle a wrapped function when I use a custom callable class as a wrapper.

我有一个可调用类"Dependee",该类跟踪成员变量为"depends_on"的包装函数的依赖关系.我想使用装饰器来包装函数,并且还可以对所得的包装函数进行腌制.

I have a callable class "Dependee" that keeps track of dependencies for a wrapped function with a member variable "depends_on". I'd like to use a decorator to wrap functions and also be able to pickle the resulting wrapped function.

因此,我定义了我的受养人课程.请注意functools.update_wrapper的使用.

So I define my dependee class. Note the use of functools.update_wrapper.

>>> class Dependee:
...     
...     def __init__(self, func, depends_on=None):
...         self.func = func
...         self.depends_on = depends_on or []
...         functools.update_wrapper(self, func)
...         
...     def __call__(self, *args, **kwargs):
...         return self.func(*args, **kwargs)
... 

然后,我定义我的装饰器,使其返回Dependee包装器类的实例.

Then I define my decorator such that it will return an instance of the Dependee wrapper class.

>>> class depends:
...     
...     def __init__(self, on=None):
...         self.depends_on = on or []
...     
...     def __call__(self, func):
...         return Dependee(func, self.depends_on)
... 

这是一个包装函数的示例.

Here's an example of a wrapped function.

>>> @depends(on=["foo", "bar"])
... def sum(x, y): return x+y
... 

该成员变量似乎可以访问.

The member variable seems to be accessible.

>>> print(sum.depends_on)
['foo', 'bar']

我可以按预期调用该函数.

I can call the function as expected.

>>> print(sum(1,2))
3

但是我不能腌制包装好的实例.

But I can't pickle the wrapped instance.

>>> print(pickle.dumps(sum))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function sum at 0x7f543863fbf8>: it's not the same object as __main__.sum

我想念什么?我如何给pickle一个更合适的限定名称,以便它可以找到实例而不是原始函数.请注意,手动换行效果很好.

What am I missing? How can I give pickle a more appropriately qualified name so that it can find the instance rather than the original function. Note that manual wrapping works just fine.

>>> def sum2_func(x,y): return x+y
... 
>>> sum2 = Dependee(sum2_func, depends_on=["foo", "bar"])
>>> print(sum2.depends_on)
['foo', 'bar']
>>> print(sum2(1,2))
3
>>> print(pickle.loads(pickle.dumps(sum2)).depends_on)
['foo', 'bar']

推荐答案

是的,众所周知的pickle问题-不能腌制不能仅通过模块中的名称检索的函数或类.参见例如 https://code.google.com/p/modwsgi/wiki/IssuesWithPickleModule提供清晰的示例(特别是有关这如何影响modwsgi的问题,以及一般情况下的问题).

Yep, well-known pickle problem -- can't pickle functions or classes that can't just be retrieved by their name in the module. See e.g https://code.google.com/p/modwsgi/wiki/IssuesWithPickleModule for clear examples (specifically on how this affects modwsgi, but also of the issue in general).

在这种情况下,由于您要做的只是向函数添加属性,因此可以采用一种简化的方法:

In this case since all you're doing is adding attributes to the function, you can get away with a simplified approach:

class depends:

def __init__(self, on=None):
    self.depends_on = on or []

def __call__(self, func):
    func.func = func
    func.depends_on = self.depends_on or []
    return func

return func是关键思想-返回正在装饰的相同对象(可能是在装饰之后,如此处所示,具有其他属性),但不是一个不同的对象,否则名称-vs-identity问题就会出现.)

the return func is the key idea -- return the same object that's being decorated (possibly after decorating it, as here, with additional attributes -- but, not a different object, else the name-vs-identity issue perks up).

现在这将起作用(只是您的原始代码,只需如上所述更改depends即可):

Now this will work (just your original code, only changing depends as above):

$ python d.py 
['foo', 'bar']
3
c__main__
sum
p0
.

当然,这不是通用解决方案(仅在装饰器返回与其装饰相同的对象可行的情况下才起作用),只是在您的示例中有效.

Of course, this isn't a general-purpose solution (it only works if it's feasible for the decorator to return the same object it's decorating), just one that works in your example.

我不知道有没有什么序列化方法可以在没有此限制的情况下对Python对象进行序列化和反序列化.

I am not aware of any serialization approach able to serialize and de-serialize Python objects without this limitation, alas.

这篇关于酸洗装饰可调用类包装器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆