【问题标题】:Strange behavior parsing JSON dicts into objects using object_hook使用 object_hook 将 JSON dicts 解析为对象的奇怪行为
【发布时间】:2011-02-04 06:13:34
【问题描述】:

我一直是exploring the json library,正在尝试将对象转换为 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 的数据是内部字典,而不是完整字典。这是为什么呢?

【问题讨论】:

    标签: python json


    【解决方案1】:

    由于您指定应使用函数 jSONToObj 重构对象,因此反序列化器假定所有 dicts 都是对象并尝试在它们上调用您的反序列化器。

    来自文档:

    object_hook 是一个可选函数 这将被调用,结果为 任何对象文字解码(字典)。 object_hook 的返回值将 被用来代替字典。这 功能可用于实现 自定义解码器(例如 JSON-RPC 类 暗示)。

    内部的dict最先被反序列化,可能是因为loads是递归工作的,从底层开始。在反序列化一个对象之前,你必须反序列化它的参数是有道理的。

    【讨论】:

    • 为什么反序列化器假定所有的字典都是对象?为什么一个对象不能包含字典?
    • 因为dicts本身没有类型注解,所以json函数永远无法分辨。您的解串器函数jSONToObj 必须自己决定什么是字典,什么不是字典,并根据需要返回对象或字典。
    • 顺便说一句,如果您只想要顶级对象,请考虑像往常一样从 JSON 中反序列化数据,然后手动将生成的 dict/list 转换为对象。
    • 是的,我意识到我误解了 object_hook 参数的用途。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多