问题 什么时候可以腌制Python对象


我正在使用多处理模块在Python中进行大量的并行处理。我知道某些对象可能是pickle(因此在multi-p中作为参数传递)而其他对象则不能。例如。

class abc():
    pass

a=abc()
pickle.dumps(a)
'ccopy_reg\n_reconstructor\np1\n(c__main__\nabc\np2\nc__builtin__\nobject\np3\nNtRp4\n.'

但是我的代码中有一些较大的类(十几种方法,或者左右),这种情况会发生:

a=myBigClass()
pickle.dumps(a)
Traceback (innermost last):
 File "<stdin>", line 1, in <module>
 File "/usr/apps/Python279/python-2.7.9-rhel5-x86_64/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle file objects

它不是文件对象,但在其他时候,我会得到其他基本上说的消息:“我不能腌制这个”。

那么规则是什么?字节数?层次深度?月相?


4232
2018-04-28 14:28


起源

你试过莳萝吗? pypi.python.org/pypi/dill   它增强了 pickle 可能性很多。 - geekazoid
我实际上只是尝试了莳萝并且它有效,但它不是我们构建的一部分,所以我将不得不从系统管理员那里请求它。仍然想知道“规则”是什么。 - Paul Nelson
@PaulNelson如果你打算用 dill,你不能使用 multiprocessing。该 dill 作者有一个 multiprocessing 叉叫 pathos 你必须改用。 - dano
@PaulNelson你可能可以逃脱实施 __getstate__/__setstate__ 在...上 myBigClass 如果你不能完全替换,那么在酸洗之前从类'状态中移除不可剔除的部分的类 multiprocessing。 - dano


答案:


我是 dill 作者。有一个相当全面的清单,其中包括什么泡菜和什么不是 dill。它可以运行每个版本的python 2.5-3.4,并根据pickles进行调整 dill 或者什么泡菜 pickle 通过改变一个标志。

看这里: https://github.com/uqfoundation/dill/blob/master/tests/test_objects.pyhttps://github.com/uqfoundation/dill/blob/master/dill/_objects.py

泡菜的规则的根源(在我的头顶):

  1. 你能通过引用捕获对象的状态(即a 功能定义于 __main__ 与导入功能相比)? [好的]
  2. 是通用的 __get_state__  __set_state__ 给定对象类型是否存在规则? [好的]
  3. 它取决于a Frame 对象(即依赖于GIL和全局执行堆栈)?迭代器现在是一个例外,由 在重新打开时“重放”迭代器。 [那就不要]
  4. 对象实例是否指向错误的类路径(即由于在闭包,C绑定或其他中定义) __init__ 路径操纵)? [那就不要]
  5. 允许这个被python认为是危险的吗? [那就不要]

因此,(5)现在不像过去那样普遍,但仍然在语言中有一些持久的影响 pickledill在大多数情况下,删除(1),(2)和(5) - 但仍然受到(3)和(4)的影响。

我可能会忘记别的东西,但我认为一般来说这些是潜在的规则。

某些模块如 multiprocessing 注册一些对其功能很重要的对象。 dill 在语言中注册大多数对象。

dill 叉子 multiprocessing 是必需的,因为 multiprocessing 使用 cPickle,和 dill 只能增加纯python酸洗注册表。如果你有耐心,你可以通过所有相关的工作 copy_reg 功能 dill,并将它们应用于 cPickle 模块,你会得到更多的酸洗能力 multiprocessing。我找到了一个简单的(读取:一个班轮)方式来做到这一点 pickle, 但不是 cPickle


3
2018-04-29 05:27



这正是我想要的。谢谢迈克 - Paul Nelson


来自 文档

可以腌制以下类型:

  • 无,真,假
  • 整数,长整数,浮点数,复数
  • 普通和Unicode字符串
  • 仅包含可选对象的元组,列表,集和词典
  • 在模块顶层定义的函数   
    • 在模块顶层定义的内置函数
  • 在模块顶层定义的类
  • 这类的实例 字典 或调用的结果 ,有getstate()是可选择的(有关详细信息,请参阅pickle协议一节)。

尝试腌制不可摧毁的对象会引发PicklingError   例外;当发生这种情况时,可能有一个未指定的字节数   已经写入底层文件。试图高度腌制   递归数据结构可能超过最大递归深度,a   在这种情况下将引发RuntimeError。你可以小心地提出这个   sys.setrecursionlimit()限制。


7
2018-04-28 14:33



正如后面文档中所述,也可以定义 __reduce__ 和 __setstate__ 和 __getstate__ 使任意对象可选择的方法,或使用持久id引用全局对象(如文件)的方法。 - Ara


除了icedtrees的回答,也直接来自 文档,您可以使用特殊方法自定义和控制类实例的pickle和unpicked: object.__getnewargs_ex__()object.__getnewargs__()object.__getstate__()object.__setstate__(state)


2
2018-04-28 14:40





一般的经验法则是“逻辑”对象可以被腌制,但“资源”对象(文件,锁)不能,因为持久化/克隆它们是没有意义的。


1
2018-04-28 14:33



我不同意它“毫无意义”。例如,内存映射数组与缓冲区数组有何不同,除非它有文件后端?在某些情况下,那些不应该被对待吗? - Mike McKerns