【发布时间】:2017-08-10 14:31:20
【问题描述】:
我有一个酸洗问题。我想在我的主脚本中序列化一个函数,然后加载它并在另一个脚本中运行它。为了证明这一点,我制作了 2 个脚本:
尝试一:天真的方式:
dill_pickle_script_1.py
import pickle
import time
def my_func(a, b):
time.sleep(0.1) # The purpose of this will become evident at the end
return a+b
if __name__ == '__main__':
with open('testfile.pkl', 'wb') as f:
pickle.dump(my_func, f)
dill_pickle_script_2.py
import pickle
if __name__ == '__main__':
with open('testfile.pkl') as f:
func = pickle.load(f)
assert func(1, 2)==3
问题:当我运行脚本 2 时,我得到AttributeError: 'module' object has no attribute 'my_func'。我明白为什么:因为当 my_func 在 script1 中序列化时,它属于 __main__ 模块。 dill_pickle_script_2 不知道那里的__main__ 引用了 dill_pickle_script_1 的命名空间,因此找不到引用。
尝试 2:插入绝对导入
我通过添加一个小技巧解决了这个问题 - 在酸洗之前,我在 dill_pickle_script_1 中添加了一个绝对导入到 my_func。
dill_pickle_script_1.py
import pickle
import time
def my_func(a, b):
time.sleep(0.1)
return a+b
if __name__ == '__main__':
from dill_pickle_script_1 import my_func # Added absolute import
with open('testfile.pkl', 'wb') as f:
pickle.dump(my_func, f)
现在可以了!但是,我想避免每次我想这样做时都必须这样做。 (另外,我想让我的酸洗在其他一些不知道 my_func 来自哪个模块的模块中完成)。
尝试 3:莳萝
我认为 dill 包可以让您在 main 中序列化内容并将它们加载到其他地方。所以我尝试了:
dill_pickle_script_1.py
import dill
import time
def my_func(a, b):
time.sleep(0.1)
return a+b
if __name__ == '__main__':
with open('testfile.pkl', 'wb') as f:
dill.dump(my_func, f)
dill_pickle_script_2.py
import dill
if __name__ == '__main__':
with open('testfile.pkl') as f:
func = dill.load(f)
assert func(1, 2)==3
然而,现在我遇到了另一个问题:运行dill_pickle_script_2.py 时,我得到了NameError: global name 'time' is not defined。似乎 dill 没有意识到 my_func 引用了 time 模块并且必须在加载时导入它。
我的问题?
我如何在 main 中序列化一个对象,然后在另一个脚本中再次加载它,以便该对象使用的所有导入也被加载,而无需在尝试 2 中进行令人讨厌的小技巧?
【问题讨论】:
-
Conchylicultor's 答案可能就是您要找的。但请记住,您还应该以二进制模式阅读腌制/挖出的文件:
open(testfile.pkl, 'rb')