Python:can';t pickle模块对象错误

Python:can';t pickle模块对象错误,python,pickle,Python,Pickle,我想上一个大班,然后 TypeError:无法pickle模块对象 尽管环顾了一下网络,我还是不能确切地理解这意味着什么。我不确定是哪个模块对象引起了问题。有办法找到罪犯吗?堆栈跟踪似乎没有任何指示。我可以通过以下方式再现错误消息: import cPickle class Foo(object): def __init__(self): self.mod=cPickle foo=Foo() with file('/tmp/test.out', 'w') as f:

我想上一个大班,然后

TypeError:无法pickle模块对象


尽管环顾了一下网络,我还是不能确切地理解这意味着什么。我不确定是哪个
模块对象
引起了问题。有办法找到罪犯吗?堆栈跟踪似乎没有任何指示。

我可以通过以下方式再现错误消息:

import cPickle

class Foo(object):
    def __init__(self):
        self.mod=cPickle

foo=Foo()
with file('/tmp/test.out', 'w') as f:
    cPickle.dump(foo, f) 

# TypeError: can't pickle module objects

您是否有引用模块的class属性?

Python无法pickle模块对象是真正的问题。有充分的理由吗?我不这么认为。让模块对象不可拼接会导致python作为并行/异步语言的脆弱性。如果您想要pickle模块对象,或者python中的几乎任何东西,那么使用
dill

Python 3.2.5 (default, May 19 2013, 14:25:55) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> import os
>>> dill.dumps(os)
b'\x80\x03cdill.dill\n_import_module\nq\x00X\x02\x00\x00\x00osq\x01\x85q\x02Rq\x03.'
>>>
>>>
>>> # and for parlor tricks...
>>> class Foo(object):
...   x = 100
...   def __call__(self, f):
...     def bar(y):
...       return f(self.x) + y
...     return bar
... 
>>> @Foo()
... def do_thing(x):
...   return x
... 
>>> do_thing(3)
103 
>>> dill.loads(dill.dumps(do_thing))(3)
103
>>> 

获取dill
here:

根据文档:

什么可以腌制和不腌制? 可以对以下类型进行酸洗:

  • 没有,真的,假的

  • 整数、浮点数、复数

  • 字符串、字节、字节数组

  • 仅包含可拾取对象的元组、列表、集和字典

  • 在模块顶层定义的函数(使用def,而不是lambda)

  • 在模块顶层定义的内置函数

  • 在模块顶层定义的类

  • 类的实例,这些类的
    \uuuuu dict\uuuu
    或调用
    \uuuuu getstate\uuuuuu()
    的结果是可pickle的(有关详细信息,请参阅Pickling Class instances一节)

如您所见,模块不在此列表中。请注意,这在使用
deepcopy
时也是正确的,并且不仅仅适用于
pickle
模块,如
deepcopy
的文档中所述:

此模块不复制诸如模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组或任何类似类型的类型。它通过原封不动地返回原始对象来“复制”函数和类(浅层和深层);这与pickle模块处理这些数据的方式兼容

一种可能的解决方法是使用
@属性
装饰器而不是属性。 例如,这应该起作用:

    import numpy as np
    import pickle

    class Foo():
        @property
        def module(self):
            return np

    foo = Foo()
    with open('test.out', 'wb') as f:
        pickle.dump(foo, f)
递归查找Pickle故障 灵感来自
wump
的评论:

下面是一些帮助我递归找到罪魁祸首的快速代码

它检查有问题的物体,看它是否不能酸洗

然后迭代尝试在
\uuu dict\uuu
中pickle键,返回仅失败pickle的列表

代码片段
导入pickle
def酸洗技巧(obj,最大深度=10):
输出={}
如果是最大深度,
.........
“ZSCORE”:},
“失败的\u子项”:[]}]}
根本原因-Redis无法pickle\u thread.lock 在我的例子中,创建我保存为对象属性的
Redis
实例破坏了pickle

当您创建
Redis
的实例时,它还会创建
线程的
连接池
,并且线程锁不能被pickle

我必须在
multiprocessing.Process
中创建并清理
Redis
,然后才能对其进行酸洗

测试 在我的例子中,我试图腌制的类,必须能够腌制。因此,我添加了一个单元测试,用于创建类的实例并对其进行pickle。这样,如果有人修改该类,使其不能被pickle,从而破坏了它在多处理(和pyspark)中使用的能力,我们将立即检测该回归并知道

def test_can_pickle():
#给定
obj=myclassthatsmustpickle()
#什么时候
pkl=pickle.dumps(obj)
#如果不再正确酸洗,此测试将抛出错误

看不到代码就很难分辨。+1。这是我见过的唯一有意义的方法(引用模块),但我不确定如何找到它。(这节课不是我自己写的,它有3500行长。)你知道我如何找到引用吗?谢谢我唯一想到的是递归下降。。对对象执行dir(…),并尝试分别pickle每个属性。取给出错误的一个,重复相同的操作,直到找到模块对象。