JSON 键在 Python 中随机排列

JSON keys are shuffled in Python

我正在从网络 api 解析 JSON,并且 Python 似乎在我遍历它们时打乱了键。

原始 JSON 屏幕截图(这是正确的原始顺序。不,它不只是按字母顺序排序):

我的代码:

data = requests.get('http://www.dota2.com/jsfeed/heropediadata?feeds=abilitydata&l=english').json()

for key in data['abilitydata']:
    print key

并输出:

tiny_avalanche
rubick_fade_bolt
doom_bringer_devour
undying_flesh_golem
...

我也尝试通过 urllib & json.loads() 来做到这一点——它给出了相同的结果。

怎样才能实现原来的排序?

因为Python 字典是无序的。

当您解析 JSON 文本时,您会得到一本字典。因为字典类型没有顺序,键只能以未定义的顺序迭代。

dict 类型是 Python 中的内置类型。它是无序的。

如果你想恢复字典中键的顺序,你可以使用 collections class.

中的 OrderedDict

看这个例子:

>>> import collections
>>> data = collections.OrderedDict()
>>> data['pear'] = 1
>>> data['apple'] = 3
>>> data['orange'] = 2
>>> data['lemon'] = 4
>>> 
>>> 
>>> print data
OrderedDict([('pear', 1), ('apple', 3), ('orange', 2), ('lemon', 4)])
>>> 
>>> 
>>> data2 = dict()
>>> data2['pear'] = 1
>>> data2['apple'] = 3
>>> data2['orange'] = 2
>>> data2['lemon'] = 4
>>> 
>>> 
>>> print data2
{'orange': 2, 'lemon': 4, 'pear': 1, 'apple': 3}
>>> 

如需了解更多信息,请阅读:https://docs.python.org/2/library/collections.html#collections.OrderedDict

正如其他人所说,dict 是无序的。 collections.OrderedDict 是一个 dict 子类,其键是有序的。问题是 json.load return 直接是 dict,我们不能直接把结果扔进 OrderedDict,因为键的顺序已经丢失了信息这一点。

我们需要一种方法来告诉 json.load 到 return 一个 OrderedDict 而不是 dict。这可以通过实现自定义 json.JSONDecoder 来完成它提供了一个 object_pairs_hookobject_pairs_hook 被赋予一个 JSON 对象作为 (key, value) 元组的列表,按照它们在 JSON 文档中出现的顺序排列。它应该 return 将此对象翻译成 Python 对象。我们将把这个元组列表传递给 collections.OrderedDict 的初始化器,这应该可以解决问题。

这是一些代码:

data = """
{
    "foo": "bar",
    "a_list": [1, 2, 3],
    "another_object": {
        "c": 3,
        "a": 1,
        "b": 2
        },
    "last_key": 42
}
"""

decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict)
result = decoder.decode(data)
print(result)

给出:

OrderedDict([('foo', 'bar'),
             ('a_list', [1, 2, 3]),
             ('another_object', OrderedDict([('c', 3), ('a', 1), ('b', 2)])),
             ('last_key', 42)])

最后,您可能想知道:"why is this so much extra work?"。好吧,JSON 并不意味着被视为具有任何固定顺序的数据结构。你这样做是有违常理的。

您可以使用有序字典和 json 包中 loads 方法的 object_pairs_hook 参数。这是一个工作代码示例:

import json
import requests
from collections import OrderedDict

result = requests.get('http://www.dota2.com/jsfeed/heropediadata?feeds=abilitydata&l=english')
data = json.loads(result.text, object_pairs_hook = OrderedDict)

数据将按顺序包含您的字典键