9

我希望能够从 __main__ 中腌制一个函数或类,但有一个明显的问题(在其他帖子中提到),腌制的函数/类位于 __main__ 命名空间中,而在另一个脚本/模块中取消腌制将失败。

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

以下在 myscript.py 中:

import myscript
import pickle

if __name__ == "__main__":               

    print pickle.dumps(myscript.myclass())

else:

    class myclass:
        pass

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

4

3 回答 3

5

Pickle 似乎着眼于类和函数定义的主要范围。从您要从中提取的模块内部,试试这个:

import myscript
import __main__
__main__.myclass = myscript.myclass
#unpickle anywhere after this
于 2014-12-30T17:20:47.120 回答
3

__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 就可以神奇地使其工作,而无需猴子修补第 3 方代码。

或者,如果您希望将整个解释器会话作为“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 序列化对象并使用并行 python、 multiprocessing 和mpi4py跨并行资源发送它们。我将这些方便地汇总到pathos包中(以及用于 MPI 的pyinamap ),它为不同的并行批处理后端提供了统一的接口。

>>> # 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]

还有非阻塞和迭代映射以及非平行管道连接。我也有一个 pathos 模块pp,但是对于__main__. 我正在努力改进它。如果你愿意,可以在 github 上 fork 代码并帮助pp改进__main__. pp不能很好地腌制的原因是pp它通过使用临时文件对象和读取解释器会话的历史来进行序列化技巧......所以它不会以与多处理或 mpi4py 相同的方式序列化对象。我有一个 dill 模块dill.source,可以无缝地执行与使用相同类型的酸洗pp,但它是相当新的。

于 2013-10-17T13:56:41.437 回答
1

如果你试图腌制一些东西,以便你可以在其他地方使用它,与 分开test_script,那是行不通的,因为 pickle (显然)只是试图从模块中加载函数。这是一个例子:

test_script.py

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

泡菜脚本.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,当你尝试加载函数时,它会失败。例如

运行这个:

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
于 2012-08-08T15:07:11.147 回答