Python和JSON:使用object_hook进行多个不同类的类型提示

0 投票
1 回答
4612 浏览
提问于 2025-04-16 00:53

在使用 Python 2.6 的 json 模块时,我在把一个函数传给 object_hook 时遇到了一些意想不到的问题。我想把一个 JSON 对象转换成我代码中定义的一个类。这个类需要传入另一个类的实例作为参数。大概是这样的:

class OuterClass:
    def __init__(self, arg, *InnerClass_instances):
        self.arg = arg
        self.class2 = InnerClass_instances

class InnerClass:
    def __init__(self, name, value):
        self.name = name
        self.value = value 

我觉得,如果要创建一个包含 OuterClass 实例所有信息的 JSON 对象,就必须把每个 InnerClass 实例的信息也包含在内。所以,我想写两个函数来解析 JSON 对象,一个处理 OuterClass,另一个处理 InnerClass,并让创建 OuterClass 的函数调用创建 InnerClass 实例的函数。大概是这样的:

def create_InnerClass(dct):
    if '__InnerClass__' in dct:
        name = dct['name']
        value = dct['value']
        return InnerClass(name, value)

def create_OuterClass(dct):
    if '__OuterClass__' in dct:
        arg = dct['arg']
        InnerClass_instances = [create_InnerClass(dct2) \
                                for dct2 in dct['InnerClass_instances']]
        return OuterClass(arg, *InnerClass_intances)

我原以为这样做是可以的:

s =            #triple quotes omitted for syntax highlighting reasons
{
"__OuterClass__": true,
"arg": 4,
"InnerClass_instances":
    [
    {"__InnerClass__": true, "name": "Joe", "value": 12},
    {"__InnerClass__": true, "name": "Jimmy", "value":7}
    ]
} 

outerClass = json.loads(s, object_hook = creat_OuterClass)

然而,像上面那样调用 json.loads 时却返回了这个错误:

if '__InnerClass__' in dct:
TypeError: argument of type 'NoneType' is not iterable

不过,简单地调用 json.loads(s),然后再用 json.dumps(outerClass) 就完全没问题。所以,看起来是我处理 object_hook 参数的方式出了问题,导致定义 InnerClass 实例的字典变成了 NoneType 对象。我是不是对 object_hook 函数在解析 JSON 对象时的用法理解错了?

有没有办法在一个 JSON 对象中为多种类进行类型提示?到目前为止,我读到的内容都没有说明这是否可行。

1 个回答

2

并不是每次调用 create_OuterClass 时,__OuterClass__ 都会出现在 dct 这个字典里。所以,你的 create_OuterClass 函数需要处理这种情况。默认情况下,它会返回 dct

def create_OuterClass(dct):
    # print('create_OuterClass: {0}'.format(dct))     
    if '__OuterClass__' in dct:
        arg = dct['arg']
        InnerClass_instances = [create_InnerClass(dct2)
                                    for dct2 in dct['InnerClass_instances']]
        return OuterClass(arg, *InnerClass_instances)
    return dct

如果你加上上面的打印语句,你会得到

create_OuterClass: {u'__InnerClass__': True, u'name': u'Joe', u'value': 12}
create_OuterClass: {u'__InnerClass__': True, u'name': u'Jimmy', u'value': 7}
create_OuterClass: {u'__OuterClass__': True, u'InnerClass_instances': [{u'__InnerClass__': True, u'name': u'Joe', u'value': 12}, {u'__InnerClass__': True, u'name': u'Jimmy', u'value': 7}], u'arg': 4}

这段内容展示了 json.loads 是如何使用 object_hook 这个回调函数的。 它首先会用内部的字典调用这个函数,之后才会用外部的字典。

撰写回答