JSON 对象中的项目是不是使用“json.dumps”出现故障?

Posted

技术标签:

【中文标题】JSON 对象中的项目是不是使用“json.dumps”出现故障?【英文标题】:Items in JSON object are out of order using "json.dumps"?JSON 对象中的项目是否使用“json.dumps”出现故障? 【发布时间】:2012-06-06 07:52:14 【问题描述】:

我正在使用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。

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

【问题讨论】:

【参考方案1】:

字典的顺序与其定义的顺序没有任何关系。所有字典都是如此,而不仅仅是那些转换为 JSON 的字典。

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

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

>>> "id":1,"name":"David","timezone":3
'timezone': 3, 'id': 1, 'name': 'David'

【讨论】:

【参考方案2】:

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

我相信较新的 pythons json 实现可以正确处理内置的 OrderedDicts,但我不确定(而且我无法轻松进行测试)。

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

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。

【讨论】:

请注意,JSON 对象仍然无序; JSON 客户端可以读取对象定义并完全忽略键的顺序并完全符合 RFC。 Martijn 是正确的,这不会影响 RFC 合规性,但如果您希望 JSON 的格式一致(例如,如果文件受版本控制,或者使人类读者更容易理解,使输入顺序与您的文档相匹配。) 在这种情况下,您只需在调用json.dumps() 时将sort_keys 设置为True;为了订单稳定性(用于测试、稳定缓存或 VCS 提交),排序键就足够了。【参考方案3】:

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'

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

Since 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 – Preserving Keyword Argument Order。

如果您的输入以 JSON 形式给出,那么为了保留顺序(获取OrderedDict),您可以传递object_pair_hook、as suggested by @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)])

【讨论】:

OrderedDict 的初始化真的很丑 @jean:初始值与OrderedDict()无关,可以将dict传递给OrderedDict(),也可以将有序对的列表传递给dict()——尽管在这两种情况下订单都会丢失。 我的意思是在保留订单时初始化它,需要输入许多'('和')' @jean:有ordereddict_literals from codetransformer package(alpha 质量) 另外,如果你使用d = json.load(f, object_pairs_hook=OrderedDict)加载JSON,后面的json.dump(d)将保留原始元素的顺序。【参考方案4】:

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

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

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

【讨论】:

这实际上是一个更好的解决方案,因为在加载时保持顺序会处理转储时间的顺序。感谢您的回答。【参考方案5】:

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

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

这对我有用

【讨论】:

完美!谢谢!【参考方案6】:

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'

【讨论】:

【参考方案7】:

如果您使用的是 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

【讨论】:

【参考方案8】:

基于 Michael Anderson 的回答,但在传入数组时也可以使用

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)

【讨论】:

以上是关于JSON 对象中的项目是不是使用“json.dumps”出现故障?的主要内容,如果未能解决你的问题,请参考以下文章

python模块------json

python模块------json

如何检查获取的响应是不是是javascript中的json对象

通过iTop Webservice接口丰富OQL的功能

使用Javascript检查JSON对象是不是包含值[重复]

Firebase 函数,响应不是有效的 json 对象