178

我正在使用json.dumps转换为 json 之类的

countries.append({"id":row.id,"name":row.name,"timezone":row.timezone})
print json.dumps(countries)

我得到的结果是:

[
   {"timezone": 4, "id": 1, "name": "Mauritius"}, 
   {"timezone": 2, "id": 2, "name": "France"}, 
   {"timezone": 1, "id": 3, "name": "England"}, 
   {"timezone": -4, "id": 4, "name": "USA"}
]

我想按以下顺序使用键:id、name、timezone - 但我有 timezone、id、name。

我应该如何解决这个问题?

4

8 回答 8

281

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}'

如果您需要特定的订单;你可以使用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}'

从 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}'

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

如果您的输入以 JSON 形式给出,那么为了保留顺序(获取OrderedDict),您可以通过@Fred Yankowski 的object_pair_hook建议 :

>>> 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)])
于 2014-05-23T03:14:57.673 回答
23

正如其他人所提到的,底层的 dict 是无序的。但是 python 中有 OrderedDict 对象。(它们是在最近的 python 中内置的,或者你可以使用这个: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)

现在使用这个我们得到:

>>> 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"}

这几乎是所希望的。

另一种选择是将编码器专门化以直接使用您的行类,然后您就不需要任何中间 dict 或 UnorderedDict。

于 2012-06-01T04:55:41.543 回答
11

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

json.dumps({'****': ***},sort_keys=False)

这对我有用

于 2019-07-19T18:20:52.497 回答
8

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

>>> {"b": 1, "a": 2}
{'a': 2, 'b': 1}

确实,字典在到达之前就被“颠倒了” json.dumps

>>> {"id":1,"name":"David","timezone":3}
{'timezone': 3, 'id': 1, 'name': 'David'}
于 2012-06-01T03:37:30.540 回答
6

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

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

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

于 2016-10-20T19:46:30.450 回答
1

基于迈克尔安德森的回答,但在您传入数组时也可以使用

class OrderedJsonEncoder(simplejson.JSONEncoder):
    def encode(self, o, first=True):
        if type(o) == list and first:
            return '[' + ",".join([self.encode(val, first=False) for val in o]) + ']'
        if type(o) == OrderedDict:
            return "{" + ",".join(
                [self.encode(k, first=False) + ":" + self.encode(v) for (k, v) in o.iteritems()]
            ) + "}"
        else:
            return simplejson.JSONEncoder.encode(self, o)
于 2021-11-13T02:12:06.960 回答
-1

如果您使用的是 Python 3.7+ ,它确实会保留顺序。

在 Python 3.7 之前,不保证 dict 是有序的,因此输入和输出通常会被打乱,除非特别要求 collections.OrderedDict。从 Python 3.7 开始,常规 dict 变成了顺序保留,因此不再需要为 JSON 生成和解析指定 collections.OrderedDict。

https://docs.python.org/3/library/json.html#json.dump

于 2021-05-05T08:28:51.963 回答
-2

Python 3.6.1:

Python 3.6.1 (default, Oct 10 2020, 20:16:48)
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import json
>>> json.dumps({'b': 1, 'a': 2})
'{"b": 1, "a": 2}'

Python 2.7.5:

Python 2.7.5 (default, Nov 20 2015, 02:00:19) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.

>>> import json
>>> json.dumps({'b': 1, 'a': 2})
'{"a": 2, "b": 1}'
于 2021-03-02T02:24:26.840 回答