读取 JSON 并将键转换为 int

Bas*_*asj 4 python json dictionary

众所周知,json将 dict 的整数键转换为字符串:

import json
print json.dumps({1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]})
# {"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}
Run Code Online (Sandbox Code Playgroud)

加载时恢复整数键的最干净的方法是什么?

d = json.loads('{"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}')
print d
# {u'1': [2.5, 2.5, 2.5], u'2': [3, 3, 3, 3]}
Run Code Online (Sandbox Code Playgroud)

我在想:

d = {int(k): d[k] for k in d}
Run Code Online (Sandbox Code Playgroud)

但是有没有一种更简洁的方法来处理带有 JSON/Python 的整数键的字典,而不需要后验的键转换?

Aus*_*tin 6

使用object_hook自定义一个函数,并执行操作:

import json

def keystoint(x):
    return {int(k): v for k, v in x.items()}

j = json.dumps({1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]})
# {"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}

print(json.loads(j, object_hook=keystoint))
# {1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]}
Run Code Online (Sandbox Code Playgroud)

文档

object_hook 是一个可选函数,将使用任何对象文字解码的结果(字典)调用。object_hook将使用的返回值代替字典。


或者,您也可以使用object_pairs_hook它让您遍历对并保存.items()调用(感谢@chepner):

import json

def keystoint(x):
    return {int(k): v for k, v in x}

j = json.dumps({1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]})
# {"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}

print(json.loads(j, object_pairs_hook=keystoint))
# {1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]}
Run Code Online (Sandbox Code Playgroud)

从文档:

object_pairs_hook 是一个可选函数,它将使用任何对象文字的结果被调用,该结果是用有序的对列表解码的。object_pairs_hook 将使用的返回值代替字典。

  • `object_pairs_hook` 稍微简单一些(保存对 `items` 方法的调用),因为它接收键/值对列表而不是字典。`loads(j, object_pairs_hook=lambda 对: {int(k): v for k,v in pair})`。 (2认同)

小智 5

如果您有嵌套字典,我还想添加另一个解决方案。


我在另一个问题下看到了这个解决方案,该问题处理普通字典和嵌套字典,如果第二层中有非整数键,则会出现错误。

>>> import json
>>> json_data = '{"1": "one", "2": {"-3": "minus three", "4": "four"}}'
>>> py_dict = json.loads(json_data, object_hook=lambda d: {int(k) 
                         if k.lstrip('-').isdigit() else k: v for k, v in d.items()})
>>> py_dict
{1: 'one', 2: {-3: 'minus three', 4: 'four'}}
Run Code Online (Sandbox Code Playgroud)

我们可以看到,object_hook用于解决问题,lstrip('-')也用于处理负值。