2015-07-02 81 views
1

嗨大家好!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']是一個函數,但它不能醃製它。

你有什麼想法如何做到這一點? 我認爲這是因爲在前一種情況下,python知道在哪裏找到函數(它在'__main__'中),但在後一種情況下,它位於'__main__'字典中我認爲如果你能告訴python這個功能的真正模塊方向,它會工作。

謝謝!

+2

_「爲了避免定義全局變量......」如果你甚至不願意在全局範圍內定義函數,你可能會把這個建議看得太遠。無論如何,'d'是全球性的,所以你在這裏並沒有真正獲得很多。 – Kevin

+0

我的意思是當我使用exec()命令時,我不喜歡它,它定義了全局變量(例如,我沒有在程序中定義f,它是在使用exec之後定義的)。這就是爲什麼我必須將所有這些變量保留在字典中。這是通過在字典 –

+0

中使用exec代碼完成的,我建議不要使用'exec'。只需定期寫下你的'def f():'。 – Kevin

回答

1

我已經找到了一個非常好的解決方案在這裏: 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

2

pickle鹹菜功能的名稱。而不是試圖轉儲和恢復字節碼,它只是說「好吧,這個功能是__main__.f,所以要取消它,請查看__main__模塊並檢索名爲f的東西」。這非常必要;如果你在解釋器環境中取消了一個函數f,其中f不存在或者做了一些不同的事情,那麼爲了保留unpickled函數的原始行爲,你需要以某種方式保留它引用的所有函數,它使用的所有模塊,所有不再存在的全局變量等。您需要確保遞歸引用ff內部使用unpickled函數,而不是新解釋器的f,這一切都變得非常糟糕。

要點是,所有的醃漬功能是全球性的。如果您查看__module__指定的模塊並查找以__name__命名的事件,則必須找到該功能,否則無法取消它。因此,你不能在假全局字典中定義函數,並且你想醃製的函數的定義是一個非常容易出錯的操作。