2017-05-05 64 views
0

我想在compile/exec中使用pickle,但它对我不起作用。它只适用于我使用全局名称空间。但我不想使用全局命名空间,有没有什么办法呢?由于pickle在编译/执行不起作用

>>> a = compile("def f():\n\t'hello'\nimport pickle\npickle.dumps(f)", "<stdin>", "exec") 
>>> exec(a)   # works 
>>> exec(a, {})  # fails 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in <module> 
_pickle.PicklingError: Can't pickle <function f at 0x1050881e0>: it's not the same object as __main__.f 
>>> exec(a, {'__name__': '__main__'}) # fails too 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in <module> 
_pickle.PicklingError: Can't pickle <function f at 0x1050882f0>: it's not the same object as __main__.f 
+0

'莳萝'咸菜功能,应该工作。 – tdelaney

+0

@tdelaney对不起,我不明白,你能解释一下吗?谢谢 – zjffdu

+0

'pickle'保存函数的文本名称,但不包含函数对象本身。 unpickler需要导入模块以获取函数。在第一种情况下,您将函数绑定到顶级脚本的全局名称空间。该名称空间被称为'__main__',所以你所做的只是加载一个名为'__main__'的模块并使用它的'f'函数。既然'__main__'和'f'都不能找到,它就无法工作。 '莳萝'咸菜功能自己,并有更好的机会为你工作。 – tdelaney

回答

1

没有,有没有办法做到这一点(没有合理反正)。函数按照合格的名称进行腌制,他们实际上并没有腌制任何部分的实现。他们通过简单地导入他们定义的模块并加载有问题的名称来取消选择。如果没有找到函数的名字空间(你用你自己定制的dict代替了__main__的全局变量,与__main__的全局变量没有关系),那么你不能pickle它,因为__main__.ff的限定名)不会在__main__的全局变量中不存在。

+0

无论如何要在compile/exec中定义模块吗? – zjffdu

+0

@zjffdu:如果将导入模块的全局变量传递给'exec',它将表现得好像在那里定义的那样。因此,例如'import os',然后'exec(a,vars(os))'会起作用,因为'f'实际上会在'os'模块上定义,并且限定名为'os.f' ,所以它可能会被腌制(任何没有为'os'模块添加一个名为'f'的函数来匹配的人都无法解除它。 – ShadowRanger