大家好!
我要做的是:
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
正如您所看到的,解决方案是构建一个新的模块,该功能将是可拾取的