如何在__main__(python)中定义的pickle函数/类

时间:2012-08-08 14:39:10

标签: python pickle

我希望能够从__main__中挑选一个函数或类,其中明显的问题(在其他帖子中提到),pickle函数/类在__main__命名空间中,而在另一个脚本/模块中进行unpickling将失败。

我有以下解决方案可行,是否有理由不应该这样做?

以下是myscript.py:

import myscript
import pickle

if __name__ == "__main__":               

    print pickle.dumps(myscript.myclass())

else:

    class myclass:
        pass

编辑:将在脚本/模块中完成unpickling,可以访问 myscript.py,并且可以执行import myscript。目的是使用类似parallel python的解决方案远程调用函数,并能够编写一个简短的独立脚本,其中包含可以远程访问的函数/类。

3 个答案:

答案 0 :(得分:2)

通过导入__main__并使用该模块中可用的方法,您可以更好地处理全局对象。这是dill为了序列化python中的几乎任何东西所做的事情。基本上,当dill序列化交互式定义的函数时,它会在序列化和反序列化方面使用__main__上的一些名称修改,使__main__成为有效的模块。

>>> import dill
>>> 
>>> def bar(x):
...   return foo(x) + x
... 
>>> def foo(x):
...   return x**2
... 
>>> bar(3)
12
>>> 
>>> _bar = dill.loads(dill.dumps(bar))
>>> _bar(3)
12

实际上,dill将它的类型注册到pickle注册表中,所以如果你有一些使用pickle的黑盒代码并且你无法真正编辑它,那么只需导入dill就可以神奇地制作它没有monkeypatching第三方代码的工作。

或者,如果您希望将整个解释器会话作为“python图像”发送,dill也可以这样做。

>>> # continuing from above
>>> dill.dump_session('foobar.pkl')
>>>
>>> ^D
dude@sakurai>$ python
Python 2.7.5 (default, Sep 30 2013, 20:15:49) 
[GCC 4.2.1 (Apple Inc. build 5566)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> dill.load_session('foobar.pkl')
>>> _bar(3)
12

您可以轻松地将图像通过ssh发送到另一台计算机,并从那里开始,只要有pickle的版本兼容性以及有关python更改和正在安装的内容的常见警告。

我实际上使用dill来序列化对象,并使用parallel python,多处理和mpi4py将它们发送到并行资源。我将这些方便地放到pathos包中(和pyina for MPI),这为不同的并行批处理后端提供了统一的map接口。

>>> # continued from above
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> Pool(4).map(foo, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>>
>>> from pyina.launchers import MpiPool
>>> MpiPool(4).map(foo, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

还有非阻塞和迭代映射以及非并行管道连接。我也有pp的pathos模块,但是,它对__main__中定义的函数有些不稳定。我正在努力改善这一点。如果您愿意,请分叉the code on github并帮助pp更好地完成__main__中定义的功能。 pp没有发现好的原因是pp通过使用临时文件对象并读取解释器会话的历史记录来执行序列化操作...因此它不会像多处理一样序列化对象还是mpi4py呢。我有一个莳萝模块dill.source,可以无缝地执行pp使用的相同类型的酸洗,但它相当新。

答案 1 :(得分:1)

如果你试图腌制某些东西,以便你可以在其他地方使用它,与test_script分开,那将无法正常工作,因为pickle(显然)只是试图加载来自模块。这是一个例子:

test_script.py

def my_awesome_function(x, y, z):
    return x + y + z

picklescript.py

import pickle
import test_script
with open("awesome.pickle", "wb") as f:
    pickle.dump(test_script.my_awesome_function, f)

如果您运行python picklescript.py,然后更改test_script的文件名,当您尝试加载该功能时,它将失败。 e.g。

运行此:

import pickle
with open("awesome.pickle", "rb") as f:
    pickle.load(f)

将为您提供以下追溯:

Traceback (most recent call last):
  File "load_pickle.py", line 3, in <module>
    pickle.load(f)
  File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 1378, in load
    return Unpickler(file).load()
  File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 858, in load
    dispatch[key](self)
  File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 1090, in load_global
    klass = self.find_class(module, name)
  File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 1124, in find_class
    __import__(module)
ImportError: No module named test_script

答案 2 :(得分:-1)

Pickle似乎在查看 main 范围,以了解类和函数的定义。从你正在取消模块的内部,试试这个:

import myscript
import __main__
__main__.myclass = myscript.myclass
#unpickle anywhere after this