有没有办法使用标准库在Python中序列化词法闭包?泡菜和元帅似乎不适用于词法封闭.我真的不关心二进制与字符串序列化等细节,它只需要工作.例如:
def foo(bar, baz) : def closure(waldo) : return baz * waldo return closure
我希望能够将闭包实例转储到文件中并将其读回.
编辑:可以解决这个问题的一个相对明显的方法是使用一些反射技巧将词法闭包转换为类对象,反之亦然.然后可以转换为类,序列化,反序列化,转换回闭包.哎呀,鉴于Python是鸭子类型,如果你重载类的函数调用操作符使它看起来像一个函数,你甚至不需要将它转换回闭包,使用它的代码不会知道区别.如果有任何Python反射API大师,请说出来.
PiCloud发布了一个开源(LGPL)pickler,可以处理函数关闭和更多有用的东西.它可以独立于云计算基础设施使用 - 它只是一个普通的选择器.这里记录了整个shebang ,您可以通过'pip install cloud'下载代码.无论如何,它做你想要的.让我们通过酸洗一个闭包来证明:
import pickle from StringIO import StringIO import cloud # generate a closure def foo(bar, baz): def closure(waldo): return baz * waldo return closure closey = foo(3, 5) # use the picloud pickler to pickle to a string f = StringIO() pickler = cloud.serialization.cloudpickle.CloudPickler(f) pickler.dump(closey) #rewind the virtual file and reload f.seek(0) closey2 = pickle.load(f)
现在我们有了closey
原始闭包,以及closey2
从字符串序列化中恢复的闭包.我们来试试吧吧.
>>> closey(4) 20 >>> closey2(4) 20
美丽.该模块是纯粹的python-你可以打开它,轻松看看是什么让魔术发挥作用.(答案是很多代码.)
如果你只是使用一个__call__
方法开始的类,它应该可以顺利使用pickle
.
class foo(object): def __init__(self, bar, baz): self.baz = baz def __call__(self,waldo): return self.baz * waldo
另一方面,将闭包转换为在运行时创建的新类的实例的hack将无法工作,因为pickle
处理类和实例的方式. pickle
不存储课程; 只有模块名称和类名.回读一个实例或类时,它会尝试导入模块并在其中找到所需的类.如果你使用了即时创建的课程,那你就不走运了.