酸洗包裹部分功能

时间:2013-01-27 18:20:44

标签: python decorator partial pickle

我正在尝试使用部分函数创建一个可选择的装饰器。但是,在尝试这样做时,我总是遇到酸洗错误。

第一个天真的例子如下:

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)

partial取自functools

稍微不那么天真的尝试包括在@wraps之上添加def wrapper一行。这没有用。

我不确定我是否理解酸洗是如何起作用的。

1 个答案:

答案 0 :(得分:7)

问题在于装饰器,而不是 partial 。一个部分对象应该正常腌制:

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

因此,您的代码的这个问题在装饰器中。它不保留原始函数的名称。试试这个:

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)

使用dd的修改应该允许pickle逻辑通过其名称发现底层函数。这就是泡菜的工作原理。

要查看pickle中的函数名称,请查看转储输出:

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

“装饰”这个词需要是可以找到的,等于底层函数,而不是被装饰者隐藏。请记住,当函数被腌制时,只会存储它们的名称。该函数的实际内容不在pickle中。

有一些解决方法,但它们并不漂亮。您可以使用 __ setstate __()来保存函数名称及其源代码。然后添加 __ getstate __()方法,通过执行其源来恢复该函数。

或者,您可以在函数对象对象中提取字节代码并保存它们。在还原时,编译代码对象并执行它。

简而言之,您使用带@符号的装饰器的目标与功能酸洗的工作原理直接相关。为了实现您的目标,您必须自定义功能酸洗,以保存功能,而不仅仅是名称。