使用 object_hook 解析 JSON 字典为对象时的奇怪行为

3 投票
1 回答
3000 浏览
提问于 2025-04-16 11:13

我一直在研究json库,想把一个对象转换成JSON数据,然后再转换回来。不过在运行这个示例代码时遇到了一些问题:

import json

class Obj:
    '''
    classdocs
    '''

    def __init__(self,s,hello="Hello world!"):
        '''
        Constructor
        '''
        self.s = s
        self.hello = hello
    def __repr__(self):
        return '<MyObj(%s,%s)>' % (self.s, self.hello)

def objToJSON(obj):
    return obj.__dict__

def jSONToObj(json):
    print(json)
    return Obj(**json)

if __name__ == '__main__':
    str = json.dumps(Obj("Hello","World"), default=objToJSON, sort_keys=True)
    print(str)
    print(json.loads(str,object_hook=jSONToObj))
    str = json.dumps(Obj("Text",{"a":"aaaa","b":"BBBBB","C":"ccccc"}), default=objToJSON, sort_keys=True)
    print(str)
    print(json.loads(str,object_hook=jSONToObj))

运行后得到的结果是:

{"hello": "World", "s": "Hello"}
{'s': 'Hello', 'hello': 'World'}
<MyObj(Hello,World)>
{"hello": {"C": "ccccc", "a": "aaaa", "b": "BBBBB"}, "s": "Text"}
{'a': 'aaaa', 'C': 'ccccc', 'b': 'BBBBB'}
Traceback (most recent call last):
  File "C:\Users\dimo414\src\test.py", line 27, in <module>
    print(json.loads(str,object_hook=jSONToObj))
  File "C:\Python31\lib\json\__init__.py", line 318, in loads
    return cls(**kw).decode(s)
  File "C:\Python31\lib\json\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Python31\lib\json\decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
  File "C:\Users\dimo414\src\test.py", line 22, in jSONToObj
    return Obj(**json)
TypeError: __init__() got an unexpected keyword argument 'a'

看起来当一个字典作为对象字典中的值时,传给jSONToObj的数据是内部字典,而不是完整的字典。这是为什么呢?

1 个回答

3

因为你指定了要用 jSONToObj 这个函数来重建对象,所以反序列化器会认为所有的字典都应该变成对象,并试图对它们调用你的反序列化函数。

根据文档:

object_hook 是一个可选的函数 会在解码任何对象字面量(一个字典)时被调用。 object_hook 的返回值 会替代原来的字典。这 个功能可以用来实现 自定义解码器(例如 JSON-RPC 类 的提示)。

内部的字典是第一个被反序列化的,可能是因为 loads 是递归工作的,从最底层开始。这也很合理,因为在反序列化一个对象之前,你得先反序列化它的参数。

撰写回答