【问题标题】:json.dumps messes up orderjson.dumps 打乱了顺序
【发布时间】:2015-05-10 14:41:00
【问题描述】:

我正在使用json module 创建一个包含类似条目的json 文件

json.dumps({"fields": { "name": "%s", "city": "%s", "status": "%s", "country": "%s" }})

但是,在创建的json-文件中,字段的顺序错误

{"fields": {"status": "%s", "city": "%s", "name": "%s", "country": "%s"}}

这是一个问题,因为 %s-strings 的替换现在不正确。

如何强制dumps 函数保持给定的顺序?

【问题讨论】:

标签: python json


【解决方案1】:

就像其他答案正确指出的那样,在 Python 3.6 之前,字典是无序的

也就是说,JSON is also supposed to have unordered mappings,所以原则上将有序字典存储在 JSON 中没有多大意义。具体来说,这意味着在读取 JSON 对象时,返回键的顺序可以是任意的。

因此,在 JSON 中保留映射顺序(如 Python OrderedDict)的一种好方法是输出一个(键、值)对数组,在读取时将其转换回有序映射:

>>> from collections import OrderedDict
>>> import json
>>> d = OrderedDict([(1, 10), (2, 20)])                                         
>>> print d[2]
20
>>> json_format = json.dumps(d.items())                   
>>> print json_format  # Order maintained
[[1, 10], [2, 20]]
>>> OrderedDict(json.loads(json_format))  # Reading from JSON: works!
OrderedDict([(1, 10), (2, 20)])
>>> _[2]  # This works!
20

(请注意有序字典是从 (key, value) 对的 list 构造的:OrderedDict({1: 10, 2: 20}) 不起作用:它的键不一定像字典文字中那样有序,因为文字创建了一个 Python 字典,其键是无序的。)

PS:从 Python 3.1 开始,json 模块 offers a hook 用于自动将一对列表(如上)转换为 OrderedDict 之类的其他内容。

【讨论】:

  • 即使 JSON 是无序的,在 json 库中对其进行有序抽象仍然很有用,原因与 OrderedDict 有用的原因相同。例如,我想输出一些 JSON 对象以供人类和机器阅读,并且我想为人类方面保留一个特定的键顺序。
  • @John B 有一种机制,请参阅下面的my answer
  • 具有一致排序的一个原因是,如果您需要生成 JSON 响应,然后构建散列以在 ETag 或缓存中使用。在这种情况下,我们不需要它以特定的顺序排列,但我们确实需要它以一致且可重复的顺序排列。每次调用它时,都应该得到相同的字符串。 json.dumps(d, sort_keys=True) 将完成。
  • 美中不足:Python 3.6+ 字典排序。
【解决方案2】:

创建json对象时可以选择OrderedDict代替普通的dict来记住插入顺序:

>>> from collections import OrderedDict
>>> a = '{"fields": { "name": "%s", "city": "%s", "status": "%s", "country": "%s" }}'
>>> b = json.loads(a, object_pairs_hook=OrderedDict)
>>> json.dumps(b)
'{"fields": {"name": "%s", "city": "%s", "status": "%s", "country": "%s"}}'

【讨论】:

  • 这很有趣。是否保证json.dumps() 保留OrderedDict b 的顺序?我在文档中找不到任何内容。
  • @EOL items = dct.items(),Lib/json/encoder.py (python3.6) 中的第 355 行。我想不出 json lib 打乱这个顺序的方法或理由。
  • 我也不是,但最好在文档中正式保证它(对于json 模块的当前和未来版本),特别是因为 JSON 本身没有任何有序集的概念键/值对 (json.org)。
  • 我创建了一个文档增强请求:bugs.python.org/issue30550
【解决方案3】:

这是一本字典,字典不按顺序排列。 你可以改用OrderedDict

您也可以添加 sort_keys=False 参数:

json.dumps(values, sort_keys=False)

【讨论】:

  • 这对写 JSON 有好处,但不利于读取:JSON 映射没有顺序,即,您从 JSON 读取的映射不保证像 JSON 文件中那样排序。
  • 我猜你的意思是dumps而不是loads?事实上,loads 默认没有任何sort_keys 参数。
  • 你是对的。我的意思是“转储”而不是“加载”。对此感到抱歉。我会编辑这个
  • sort_keys 已经默认为 False,所以这不会改变任何东西。 json.dumps 不会保留提供的 OrderedDict 中的键顺序
【解决方案4】:

您不能从字典创建 OrderedDict,因为在您创建字典时顺序已经改变。所以最好的方法是使用元组来创建 OrderedDict

from collections import OrderedDict
import json

a = (("name","foo"),("city","bar"),("status","baz"),("country","my"))

b = OrderedDict(a)

c = {"fileds": b}

print json.dumps(c)
Output:
{"fileds": {"name": "foo", "city": "bar", "status": "baz", "country": "my"}}

【讨论】:

  • JSON 没有有序映射的概念,因此原则上将 OrderedDict b 转储为 JSON 可以更改键顺序。正如我的回答一样,您必须转储 OrderedDict 的 .items()。此外,不需要您使用 c 变量添加的间接寻址:它没有任何效果(但会使代码复杂化)。
  • 谢谢..我不知道这个
【解决方案5】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    • 2020-09-13
    • 1970-01-01
    相关资源
    最近更新 更多