什么时候可以 pickle Python 对象

When can a Python object be pickled

我正在 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

它不是文件对象,但在其他时候,我会收到其他消息,基本上是:"I can't pickle this".

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

来自docs

The following types can be pickled:

  • None, True, and False
  • integers, long integers, floating point numbers, complex numbers
  • normal and Unicode strings
  • tuples, lists, sets, and dictionaries containing only picklable objects
  • functions defined at the top level of a module
    • built-in functions defined at the top level of a module
  • classes that are defined at the top level of a module
  • instances of such classes whose __dict__ or the result of calling __getstate__() is picklable (see section The pickle protocol for details).

Attempts to pickle unpicklable objects will raise the PicklingError exception; when this happens, an unspecified number of bytes may have already been written to the underlying file. Trying to pickle a highly recursive data structure may exceed the maximum recursion depth, a RuntimeError will be raised in this case. You can carefully raise this limit with sys.setrecursionlimit().

一般的经验法则是 "logical" 对象可以被 pickle,但是 "resource" 对象(文件,锁)不能,因为 persist/clone 它们没有意义.

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

我是 dill 的作者。作为 dill 的一部分,有一个相当全面的清单,其中列出了泡菜和不泡菜的内容。它可以是每个 Python 2.5–3.4 版本的 运行,并通过更改一个标志来调整用 dill 腌制的内容或用 pickle 腌制的内容。参见 here and here

泡菜规则的根源是什么(我想不起来了):

  1. 你能通过引用捕获对象的状态吗(即一个 __main__ 中定义的函数与导入的函数)? [那么,是的]
  2. 给定对象类型是否存在通用 __getstate____setstate__ 规则? [那么,是的]
  3. 它是否依赖于 Frame 对象(即依赖于 GIL 和全局执行堆栈)?迭代器现在是一个例外,"replaying" unpickling 上的迭代器。 [那么,没有]
  4. 对象实例是否指向错误的 class 路径(即由于在闭包、C 绑定或其他 __init__ 路径操作中定义)? [那么,没有]
  5. Python 认为允许这样做是危险的吗? [那么,没有]

因此,(5) 现在不像以前那么流行了,但在 pickle 的语言中仍然有一些持久的影响。 dill,在大多数情况下,删除了 (1)、(2) 和 (5) – 但仍然受到 (3) 和 (4) 的影响。

我可能忘记了其他东西,但我认为一般来说这些是基本规则。

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

multiprocessingdill 分支是必需的,因为 multiprocessing 使用 cPickle,而 dill 只能扩充纯 Python酸洗注册表。如果你有耐心,你可以通过 dill 中所有相关的 copy_reg 函数,并将它们应用到 cPickle 模块,你会得到一个更 pickle-capable multiprocessing。我找到了一种简单的(阅读:一个班轮)方法来为 pickle 执行此操作,但不是 cPickle.