2015-08-20 22 views
5

我正在解析来自web api的JSON,并且当我遍历它们时,Python似乎洗牌了这些密钥。JSON密钥在Python中被洗牌

上的截图原始JSON(这是正确的原始顺序号,它不只是按字母顺序排序): Original 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() - 它给出了相同的结果。

我该如何才能实现原来的订购?

+0

您能通过对象阅读它,当你阅读每一个对象添加次序键。我从来没有与JSON合作过,但我会想象像先读取文件,然后迭代每个对象,并将它转换为JSON时添加一个新属性 - 原始顺序 – PyNEwbie

+1

JSON对象是[定义](http:///www.json.org),“一组无名称/值对”。如果键值对最初指定的顺序很重要,那么你真的不应该使用JSON对象(或者甚至不应该使用JSON)。 –

回答

5

您可以在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) 

数据将包含字典键,以便

+0

谢谢,这对我有用&这是最短的解决方案:) – arts777

1

因为Python字典是无序的。

当你解析JSON文本时,你会得到一个字典。由于字典类型没有顺序,所以只能以未定义的顺序迭代键。

+0

感谢您的解释。有没有办法用原来的顺序迭代它? – arts777

+6

即使在使用维护顺序的Python类型(即,必须通过直通式使用的orderedict)仍然不正确以在JSON中依赖此行为, JSON本身明确地建立* no *键/值的排序。 – user2864740

+0

@ user2864740这只是实用程序解析器,不是与生产相关的代码:) – arts777

1

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

如果您希望能够恢复字典中键的顺序,可以使用collections类中的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

3

正如其他人所说,dict是无序的。 collections.OrderedDict是一个字典子类,其键的顺序。问题是json.load直接返回dict,我们不能只将结果放在OrderedDict中,因为按键的顺序已经失去了信息。

我们需要告诉json.load通过实现自定义json.JSONDecoder它提供了object_pairs_hook返回一个OrderedDict而不是dict。这是可以做到的方式。 object_pairs_hook被给予一个JSON对象作为它们出现在JSON文档中的顺序列表的(key, value)元组。它应该将该对象的翻译返回给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)]) 

最后,你可能会疑惑: “这是为什么这么多的工作?”。那么,JSON并不意味着被视为具有任何固定顺序的数据结构。你这样做是违背了粮食的。

+0

谢谢!很好的解释。 – arts777