在 python 中选择并执行

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

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

你知道怎么做吗? 我认为这是因为在前一种情况下,python 知道在哪里可以找到该函数(它在“__main__”中),但在后一种情况下,它在位于“[=29”的字典中=]' 我觉得如果你能告诉python这个函数真正的模块方向,就可以了。

谢谢!

pickle 按名称腌制函数。它没有尝试转储和恢复字节码,而是说 "okay, this function is __main__.f, so to unpickle it, look in the __main__ module and retrieve the thing called f"。这几乎是必要的;如果您在 f 不存在的解释器环境中取消函数 f 或做一些不同的事情,那么为了保留取消函数的原始行为,您需要以某种方式保留所有函数它引用,它使用的所有模块,所有不再存在的全局变量等。您需要确保 f 内部对 f 的递归引用使用 unpickled 函数新解释器的f,这一切都变得一团糟。

关键在于 pickled 函数 是全局的。如果你在他们的 __module__ 指定的模块中寻找他们的 __name__ 命名的东西,你必须找到函数,否则你无法解开它。因此,您不能 exec 伪造的全局字典中的函数定义,并且执行您想要 pickle 的函数定义是一个非常容易出错的操作。

我在这里找到了一个非常好的解决方案: Dynamically importing Python module

解决上述问题的代码是这样的:

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

如你所见,解决方案是构建一个新模块,函数将被 pickleable