使用示例
def foo(a):
def bar(b):
return a+b
return bar
d = {1:foo(1), 2:foo(2)}
似乎pickle模块不能使用未在模块范围定义的功能,因此酸洗'd'将不起作用。我还应该考虑另一种酸洗机制吗?
答案 0 :(得分:14)
我担心你不能腌制嵌套函数。
pickle
模块按名称序列化函数。也就是说,如果模块myfunc
中有一个函数mymodule
,它只会保存名称mymodule.myfunc
并在反序列化时再次查找。 (这是一个重要的安全性和兼容性问题,因为它保证了反序列化代码使用自己的函数定义,而不是可能被破坏或过时的原始定义。)
唉,pickle
不能用嵌套函数做到这一点,因为没有办法直接通过名字来解决它们。例如,无法从bar
以外访问您的foo
函数。
如果您需要一个像函数一样工作的可序列化对象,您可以使用__call__
方法创建一个类:
class foo(object):
def __init__(self, a):
self.a = a
def __call__(self, b): # the function formerly known as "bar"
return self.a + b
这就像问题中的嵌套函数一样,并且应该对pickle
没有任何问题。但请注意,在反序列化foo
实例时,您需要具有相同的类定义。
答案 1 :(得分:3)
如果您使用dill
而非pickle
,则可以腌制嵌套函数。
>>> import dill
>>>
>>> def foo(a):
... def bar(b):
... return a+b
... return bar
...
>>> d = {1:foo(1), 2:foo(2)}
>>>
>>> _d = dill.dumps(d)
>>> d_ = dill.loads(_d)
>>> d_
{1: <function bar at 0x108cfe848>, 2: <function bar at 0x108cfe8c0>}
>>> d[1](0) + d[2](10)
13
>>>
答案 2 :(得分:0)
根据Blckknght的回答。如果嵌套函数是唯一的Extrac序列化类型,并将其用作decorator
,则只需在内部函数定义的顶部添加functools.warps
即可导致其他解释找到正确的名称:
from functools import warps
def foo(func):
@wraps(func)
def bar(b):
return func(b)
return bar
@foo
def zzz(b):
return b