Python多线程:管理字典不可序列化

2 投票
2 回答
2937 浏览
提问于 2025-04-17 17:33

我在一个Python脚本里实现了多线程。我使用了多进程模块里的管理器来创建并在多个线程之间共享一个字典。

在我的脚本结束时,我想把这个字典输出为JSON格式并保存到一个文件里,所以我这样做:

output = open(args.file,'w')
output.write(json.dumps(data))

但是我遇到了一个错误,提示我说这个管理器的字典无法被序列化:

TypeError: <DictProxy object, typeid 'dict' at 0x2364210> is not JSON serializable

那我该怎么才能把我的字典序列化呢?我是不是需要把键值对复制到另一个普通的字典里?

2 个回答

0

... "挺"简单的。

我看到过这个问题的回答

我需要对字典的键使用iter(),这样才能创建一个新的“普通”的字典,这样它就可以被序列化了。

4

如果字典的值都是可以序列化的

看起来,只要把 DictProxy 传给 dict 的构造函数,就可以把数据转换成 JSON 格式。下面的例子是用 Python 3.6 写的:

>>> import multiprocessing, json
>>> m = multiprocessing.Manager()
>>> d = m.dict()
>>> d["foo"] = "bar"
>>> d
<DictProxy object, typeid 'dict' at 0x2a4d630>
>>> dict(d)
{'foo': 'bar'}
>>> json.dumps(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
TypeError: Object of type 'DictProxy' is not JSON serializable
>>> json.dumps(dict(d))
'{"foo": "bar"}'

如你所见,虽然 d 是一个 DictProxy,但使用 json.dumps(dict(d)) 而不是 json.dumps(d),就能成功把数据序列化。如果你使用 json.dump,同样的道理也适用。

如果字典中的某些值也是 DictProxies

不幸的是,如果 DictProxy 中的某个值也是 DictProxy,那么上面的方法就不管用了。这个例子中就创建了这样的值:

>>> import multiprocessing
>>> m = multiprocessing.Manager()
>>> d = m.dict()
>>> d["foo"] = m.dict()

解决这个问题的方法是扩展 json.JSONEncoder 类,以便处理 DictProxy 对象,像这样:

>>> import multiprocessing, json
>>> class JSONEncoderWithDictProxy(json.JSONEncoder):
...     def default(self, o):
...             if isinstance(o, multiprocessing.managers.DictProxy):
...                     return dict(o)
...             return json.JSONEncoder.default(self, o)
...
>>> m = multiprocessing.Manager()
>>> d = m.dict()
>>> d["foo"] = m.dict()
>>> d["foo"]["bar"] = "baz"
>>> json.dumps(d, cls=JSONEncoderWithDictProxy)
'{"foo": {"bar": "baz"}}'
>>> # This also works:
>>> JSONEncoderWithDictProxy().encode(d)
'{"foo": {"bar": "baz"}}'

当 JSON 编码器遇到 DictProxy 时,它会把它转换成 dict,然后再进行编码。想了解更多信息,可以查看 Python 文档

撰写回答