您可以使用
JSONDecoder.object_pairs_hook
来自定义
JSONDecoder
解码对象的方式。此钩子函数将接收到一个由
(key, value)
对组成的列表,您通常会对这些对进行一些处理,然后转换为
dict
。
然而,由于 Python 字典不允许有重复的键(您无法更改这一点),因此您可以在钩子中保持这些对不变,并在解码 JSON 时获得一个嵌套的
(key, value)
对列表:
from json import JSONDecoder
def parse_object_pairs(pairs):
return pairs
data = """
{"foo": {"baz": 42}, "foo": 7}
"""
decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj
输出:
[(u'foo', [(u'baz', 42)]), (u'foo', 7)]
如何使用这个数据结构完全取决于您。如上所述,Python字典不允许重复的键,并且没有任何方法可以绕过这一点。你怎么查找一个键呢?dct[key]
会产生歧义。
因此,您可以实现自己的逻辑来处理期望工作方式的查找,或者实现某种冲突避免以使键唯一(如果它们不是),然后从嵌套列表创建一个字典。
编辑:由于您想要修改重复的键以使其唯一,这是如何做到的:
from collections import OrderedDict
from json import JSONDecoder
def make_unique(key, dct):
counter = 0
unique_key = key
while unique_key in dct:
counter += 1
unique_key = '{}_{}'.format(key, counter)
return unique_key
def parse_object_pairs(pairs):
dct = OrderedDict()
for key, value in pairs:
if key in dct:
key = make_unique(key, dct)
dct[key] = value
return dct
data = """
{"foo": {"baz": 42, "baz": 77}, "foo": 7, "foo": 23}
"""
decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj
输出:
OrderedDict([(u'foo', OrderedDict([(u'baz', 42), ('baz_1', 77)])), ('foo_1', 7), ('foo_2', 23)])
make_unique
函数负责返回一个无冲突的键。在这个例子中,它只是用 _n
后缀键名,其中 n
是递增计数器 - 可根据需要进行调整。
因为 object_pairs_hook
恰好按照 JSON 文档中出现的顺序接收到这些键值对,所以也可以通过使用 OrderedDict
来保留该顺序,我也将其包含在内。