Pickle and exec in python



大家好!

我要做的是:

import pickle
exec "def f():    print 'Hi!'"
code = pickle.dumps(f)
print code

正如你所看到的,它运行良好。

但是,为了避免定义全局变量(例如前面代码中的f(,我想做这样的事情:

import pickle
d = {}
exec "def f():    print 'Hi!'" in d
d['f']()
code = pickle.dumps(d['f'])
print code

上面印着"嗨!",这意味着python将d['f']识别为一个函数,但它不能pickle它。

你知道怎么做吗?我认为这是因为在前一种情况下,python知道在哪里可以找到函数(它在'__main__'中(,但在后一种情况中,它在'___main__'的字典中。我认为,如果你能告诉python这个函数的真正模块方向,它就会起作用。

谢谢!

pickle按名称pickle函数。与其尝试转储和恢复字节码,它只是说"好吧,这个函数是__main__.f,所以要取消拾取它,请查看__main__模块并检索名为f的东西"。这是非常必要的;如果在f不存在或执行不同操作的解释器环境中取消拾取函数f,那么为了保留未拾取函数的原始行为,您需要以某种方式保留它引用的所有函数、使用的所有模块、不再存在的所有全局变量等。您需要确保f中对f的递归引用使用了unpickled函数,而不是新解释器的f,这一切都会变得一团糟。

这一切的重点是,pickled函数具有全局性。如果你在他们的__module__指定的模块中查找__name__命名的东西,你必须找到这个函数,否则你就无法解开它。因此,你无法在假全局字典中exec这个函数定义,而执行你想要pickle的函数定义是一个非常容易出错的策略。

我在这里找到了一个非常好的解决方案:动态导入Python模块

解决上述问题的一个代码是:

import pickle
import sys
import imp
foo = imp.new_module("foo")
sys.modules["foo"] = foo
exec "def f():    print 'Hi!'" in foo.__dict__
code = pickle.dumps(foo.f)
print code

正如您所看到的,解决方案是构建一个新的模块,该功能将是可拾取的

最新更新