我正在尝试挑选一个大班并获得“TypeError:无法挑选模块对象”。尽管环顾网络,但我无法弄清楚这意味着什么。我不确定哪个“模块对象”造成了麻烦。有没有办法找到罪魁祸首?堆栈跟踪似乎没有任何表示。
答案 0 :(得分:10)
受wump
的评论启发:
Python: can't pickle module objects error
这里有一些快速的代码可以帮助我递归地找到罪魁祸首。
它检查有问题的对象以查看其酸洗是否失败。
然后迭代尝试对__dict__
中的键进行腌制,返回仅失败的腌制列表。
import pickle
def pickle_trick(obj, max_depth=10):
output = {}
if max_depth <= 0:
return output
try:
pickle.dumps(obj)
except (pickle.PicklingError, TypeError) as e:
failing_children = []
if hasattr(obj, "__dict__"):
for k, v in obj.__dict__.items():
result = pickle_trick(v, max_depth=max_depth - 1)
if result:
failing_children.append(result)
output = {
"fail": obj,
"err": e,
"depth": max_depth,
"failing_children": failing_children
}
return output
import redis
import pickle
from pprint import pformat as pf
def pickle_trick(obj, max_depth=10):
output = {}
if max_depth <= 0:
return output
try:
pickle.dumps(obj)
except (pickle.PicklingError, TypeError) as e:
failing_children = []
if hasattr(obj, "__dict__"):
for k, v in obj.__dict__.items():
result = pickle_trick(v, max_depth=max_depth - 1)
if result:
failing_children.append(result)
output = {
"fail": obj,
"err": e,
"depth": max_depth,
"failing_children": failing_children
}
return output
if __name__ == "__main__":
r = redis.Redis()
print(pf(pickle_trick(r)))
$ python3 pickle-trick.py
{'depth': 10,
'err': TypeError("can't pickle _thread.lock objects"),
'fail': Redis<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>,
'failing_children': [{'depth': 9,
'err': TypeError("can't pickle _thread.lock objects"),
'fail': ConnectionPool<Connection<host=localhost,port=6379,db=0>>,
'failing_children': [{'depth': 8,
'err': TypeError("can't pickle _thread.lock objects"),
'fail': <unlocked _thread.lock object at 0x10bb58300>,
'failing_children': []},
{'depth': 8,
'err': TypeError("can't pickle _thread.RLock objects"),
'fail': <unlocked _thread.RLock object owner=0 count=0 at 0x10bb58150>,
'failing_children': []}]},
{'depth': 9,
'err': PicklingError("Can't pickle <function Redis.<lambda> at 0x10c1e8710>: attribute lookup Redis.<lambda> on redis.client failed"),
'fail': {'ACL CAT': <function Redis.<lambda> at 0x10c1e89e0>,
'ACL DELUSER': <class 'int'>,
0x10c1e8170>,
.........
'ZSCORE': <function float_or_none at 0x10c1e5d40>},
'failing_children': []}]}
就我而言,创建我保存为对象属性的Redis
实例会破坏酸洗。
创建Redis
的实例时,它还会创建connection_pool
的{{1}},并且无法腌制线程锁。
在腌制之前,我必须在Threads
中创建和清理Redis
。
就我而言,我尝试腌制的班级,必须必须腌制。因此,我添加了一个单元测试,该测试创建该类的实例并将其腌制。这样,如果有人修改了该类以使其不能被腌制,从而破坏了它在多处理(和pyspark)中使用的能力,我们将检测到该回归并立即知道。
multiprocessing.Process
答案 1 :(得分:8)
我可以通过这种方式重现错误消息:
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
您是否有引用模块的类属性?
答案 2 :(得分:7)
Python无法挑选模块对象是真正的问题。有充分的理由吗?我不这么认为。让模块对象不可分割会导致python作为并行/异步语言的脆弱性。如果你想在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
:https://github.com/uqfoundation/dill
答案 3 :(得分:0)
根据文档:
什么可以腌制和不腌制?
可以腌制以下类型:
无,真与假
整数,浮点数,复数
字符串,字节,字节数组
仅包含可拾取对象的元组,列表,集合和词典
在模块顶层定义的功能(使用def,而不是lambda)
- 在模块的顶层定义的
在模块顶层定义的内置函数
- 此类{<1>}或调用
类
__dict__
的结果是可腌制的类的实例(有关详细信息,请参见“腌制类实例”一节)。
如您所见,模块不属于此列表。请注意,如__getstate__()
的文档所述,不仅在deepcopy
模块中使用pickle
,这也是正确的:
此模块不复制诸如模块,方法,堆栈跟踪,堆栈框架,文件,套接字,窗口,数组或任何类似类型的类型。它通过不变地返回原始对象来“复制”函数和类(浅层和深层)。这与咸菜模块处理这些食物的方式兼容。
可能的解决方法是使用deepcopy
装饰器而不是属性。
例如,这应该起作用:
@property