2017-05-05 52 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