将Python的json.loads()对象钩子参数化为工厂方法

2 投票
1 回答
1935 浏览
提问于 2025-04-18 15:00

我现在正在写一个应用程序,使用Python的JSON模块,觉得把JSON数据转化成合适的Python对象会很不错。

下面的代码运行得很好。

Class MyClass :
    def __init__(self, argA = None, argB = None, ... , JSON_Object=None):
        self.attrA = argA
        self.attrB = argB
        ...

        if JSON_Object :
            self.attrA = json.loads(JSON_Object, object_hook=self._getAttributeA)
            self.attrB = json.loads(JSON_Object, object_hook=self._getAttributeB)
            ...

    # Individual call back functions for the init... *yucky*.
    def _getAttributeA(self, JSON_Object) :
        if 'attrA' in JSON_Object :
            return JSON_Object['attrA']

    def _getAttributeB(self, JSON_Object) :
        if 'attrB' in JSON_Object :
            return JSON_Object['attrB']

    ...

不过,当属性超过五个的时候,每个属性都要重新写函数就有点烦人了。考虑到这里其实可以用工厂方法来解决,所需的只不过是一些参数。

我该怎么模拟这个呢?

我多次查看了Python的JSON文档,但我很沮丧,为什么这个功能不是立刻就能实现的呢?

Class MyClass :
    def __init__(self, argA=None, argB=None, ..., JSON_Object=None):
        self.attrA = argA
        self.attrB = argB
        ...

        if JSON_Object :
            self.attrA = json.loads(JSON_Object, object_hook=self._getAttribute, args=["attrA"])
            self.attrB = json.loads(JSON_Object, object_hook=self._getAttribute, args=["arrtB"])
            ...

    # super simple, general, parameterized callback function for json.loads()
    def _getAttribute(self, JSON_Object, args) :
        if args[0] in JSON_Object :
            return JSON_Object[args[0]]

一个复杂的解决方案也可以,但更大的问题是,为什么这不能立刻实现呢??

1 个回答

1

你用object_hook的方式真有点奇怪。object_hook是用来定制反序列化过程的,目的是把字典转换成其他数据类型,而不是用来从JSON中读取字段。如果你只是想读取字段,应该直接用loads来加载JSON,不用object_hook,然后用普通的索引语法从得到的字典中读取字段:

data = json.loads(JSON_Object)
self.attrA = data['attrA']
self.attrB = data['attrB']
...

或者如果你想把所有字段都放到同名的对象属性里:

self.__dict__.update(json.loads(JSON_Object))

如果你想递归地应用这个,那时候用object_hook就合适了:

class JSON_Namespace(object):
    def __init__(self, data_dict):
        self.__dict__.update(data_dict)
    @classmethod
    def load_from_json(cls, json_string):
        return json.loads(json_string, object_hook=cls)

撰写回答