JSON对象中的项目使用"json.dumps"乱序?

Noo*_*oor 140 python json

我正在使用json.dumps像json转换成json

countries.append({"id":row.id,"name":row.name,"timezone":row.timezone})
print json.dumps(countries)
Run Code Online (Sandbox Code Playgroud)

我的结果是:

[
   {"timezone": 4, "id": 1, "name": "Mauritius"}, 
   {"timezone": 2, "id": 2, "name": "France"}, 
   {"timezone": 1, "id": 3, "name": "England"}, 
   {"timezone": -4, "id": 4, "name": "USA"}
]
Run Code Online (Sandbox Code Playgroud)

我希望按以下顺序拥有密钥:id,name,timezone - 但我有时区,id,名称.

我该怎么解决这个问题?

jfs*_*jfs 217

Python dict(在Python 3.7之前)和JSON对象都是无序集合.您可以传递sort_keys参数,对键进行排序:

>>> import json
>>> json.dumps({'a': 1, 'b': 2})
'{"b": 2, "a": 1}'
>>> json.dumps({'a': 1, 'b': 2}, sort_keys=True)
'{"a": 1, "b": 2}'
Run Code Online (Sandbox Code Playgroud)

如果您需要特定订单; 你可以使用collections.OrderedDict:

>>> from collections import OrderedDict
>>> json.dumps(OrderedDict([("a", 1), ("b", 2)]))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict([("b", 2), ("a", 1)]))
'{"b": 2, "a": 1}'
Run Code Online (Sandbox Code Playgroud)

从Python 3.6开始,保留了关键字参数顺序,并且可以使用更好的语法重写上述内容:

>>> json.dumps(OrderedDict(a=1, b=2))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict(b=2, a=1))
'{"b": 2, "a": 1}'
Run Code Online (Sandbox Code Playgroud)

请参阅PEP 468 - 保留关键字参数顺序.

如果你的输入给出JSON然后保存顺序(得到OrderedDict),你可以传递object_pair_hook, 通过@Fred Yankowski的建议:

>>> json.loads('{"a": 1, "b": 2}', object_pairs_hook=OrderedDict)
OrderedDict([('a', 1), ('b', 2)])
>>> json.loads('{"b": 2, "a": 1}', object_pairs_hook=OrderedDict)
OrderedDict([('b', 2), ('a', 1)])
Run Code Online (Sandbox Code Playgroud)

  • 此外,如果使用`d = json.load(f,object_pairs_hook = OrderedDict)`加载JSON,则稍后的`json.dump(d)`将保留原始元素的顺序. (23认同)
  • @jean:初始值与`OrderedDict()`无关,你可以将`dict`传递给`OrderedDict()`,你也可以将一个有序对的列表传递给`dict()` - 尽管在这两种情况下,订单都会丢失. (3认同)
  • OrderedDict 的 init 真的很丑 (2认同)

Mic*_*son 21

正如其他人所提到的,潜在的字典是无序的.但是在python中有OrderedDict对象.(它们是在最近的蟒蛇中内置的,或者你可以使用它:http://code.activestate.com/recipes/576693/).

我相信较新的pythons json实现正确处理内置的OrderedDicts,但我不确定(我没有轻松访问测试).

旧的pythons simplejson实现不能很好地处理OrderedDict对象..并在输出它们之前将它们转换为常规dicts ..但是你可以通过执行以下操作来克服这个问题:

class OrderedJsonEncoder( simplejson.JSONEncoder ):
   def encode(self,o):
      if isinstance(o,OrderedDict.OrderedDict):
         return "{" + ",".join( [ self.encode(k)+":"+self.encode(v) for (k,v) in o.iteritems() ] ) + "}"
      else:
         return simplejson.JSONEncoder.encode(self, o)
Run Code Online (Sandbox Code Playgroud)

现在使用这个我们得到:

>>> import OrderedDict
>>> unordered={"id":123,"name":"a_name","timezone":"tz"}
>>> ordered = OrderedDict.OrderedDict( [("id",123), ("name","a_name"), ("timezone","tz")] )
>>> e = OrderedJsonEncoder()
>>> print e.encode( unordered )
{"timezone": "tz", "id": 123, "name": "a_name"}
>>> print e.encode( ordered )
{"id":123,"name":"a_name","timezone":"tz"}
Run Code Online (Sandbox Code Playgroud)

这几乎是所希望的.

另一种方法是专门编码器直接使用你的行类,然后你不需要任何中间字典或UnorderedDict.

  • 请注意,JSON对象仍然是*无序的*; JSON客户端可以读取对象定义并完全忽略密钥的顺序,并完全符合RFC. (5认同)
  • Martijn是正确的,这不会影响RFC合规性,但如果您希望为JSON提供一致的格式(例如,如果文件受版本控制,或者使人类读者更容易),它肯定仍然有价值.理解,使入场顺序与您的文件相符.) (4认同)
  • 在这种情况下,您只需在调用`json.dumps()`时将`sort_keys`设置为`True`; 对于订单稳定性(用于测试,稳定缓存或VCS提交),排序键就足够了. (3认同)

小智 9

嘿,我知道这个答案太晚了,但添加 sort_keys 并为它分配 false 如下:

json.dumps({'****': ***},sort_keys=False)
Run Code Online (Sandbox Code Playgroud)

这对我有用

  • 默认值已经是 False。 (4认同)

Dav*_*son 7

字典的顺序与其定义的顺序没有任何关系.所有字典都是如此,而不仅仅是那些变成JSON的字典.

>>> {"b": 1, "a": 2}
{'a': 2, 'b': 1}
Run Code Online (Sandbox Code Playgroud)

事实上,这本字典甚至在达到之前就被"颠倒了" json.dumps:

>>> {"id":1,"name":"David","timezone":3}
{'timezone': 3, 'id': 1, 'name': 'David'}
Run Code Online (Sandbox Code Playgroud)


mar*_*ing 6

json.dump() 将保留字典的顺序。在文本编辑器中打开文件,您将看到。无论您是否向它发送 OrderedDict,它都会保留订单。

但是 json.load() 将丢失保存对象的顺序,除非您告诉它加载到 OrderedDict() 中,这是按照 JFSebastian 上面的指示使用 object_pairs_hook 参数完成的。

否则它会丢失顺序,因为在通常的操作下,它会将保存的字典对象加载到常规 dict 中,而常规 dict 不会保留给定项目的 oder。