我可以在json.dump中使用OrderedDict。也就是说,OrderedDict可以用作JSON的输入。
json.dump
但它能被用作输出吗?如果是,怎么做?在我的情况下,我想load到一个OrderedDict,这样我可以保持文件中的键的顺序。
load
如果不是,有没有什么解决办法?
除了转储字典之外,您总是可以写出键的列表,然后通过遍历列表重新构造OrderedDict ?
OrderedDict
是的,你可以。通过将object_pairs_hook参数指定为JSONDecoder。事实上,这正是文档中给出的示例。
object_pairs_hook
>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1, "bar": 2}') OrderedDict([('foo', 1), ('bar', 2)]) >>>
你可以像这样将这个参数传递给json.loads(如果你不需要Decoder实例用于其他目的):
json.loads
>>> import json >>> from collections import OrderedDict >>> data = json.loads('{"foo":1, "bar": 2}', object_pairs_hook=OrderedDict) >>> print json.dumps(data, indent=4) { "foo": 1, "bar": 2 } >>>
使用json.load的方法是一样的:
json.load
>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)
Python 2.7+的简单版本
my_ordered_dict = json.loads(json_str, object_pairs_hook=collections.OrderedDict)
或者适用于Python 2.4到2.6
import simplejson as json import ordereddict my_ordered_dict = json.loads(json_str, object_pairs_hook=ordereddict.OrderedDict)
除了在字典旁边转储键的有序列表外,另一个低技术含量的解决方案(具有显式的优点)是转储键-值对的(有序)列表ordered_dict.items();loading是一个简单的OrderedDict(<list of key-value pairs>)。这处理了一个有序字典,尽管JSON没有这个概念(JSON字典没有顺序)。
ordered_dict.items()
OrderedDict(<list of key-value pairs>)
利用json以正确的顺序转储OrderedDict这一事实确实很好。然而,将所有 JSON字典读取为OrderedDict(通过object_pairs_hook参数)通常是不必要的沉重且没有必要的意义,因此显式转换只有必须排序的字典也是有意义的。
json
如果指定object_pairs_hook参数,通常使用的load命令将有效:
import json from collections import OrderedDict with open('foo.json', 'r') as fp: metrics_types = json.load(fp, object_pairs_hook=OrderedDict)
好消息!从3.6版开始,cPython实现保留了字典的插入顺序(https://mail.python.org/pipermail/python-dev/2016-September/146327.html)。这意味着json库现在默认是有序保存的。观察python 3.5和3.6之间的行为差异。代码:
import json data = json.loads('{"foo":1, "bar":2, "fiddle":{"bar":2, "foo":1}}') print(json.dumps(data, indent=4))
在py3.5中,结果顺序未定义:
{ "fiddle": { "bar": 2, "foo": 1 }, "bar": 2, "foo": 1 }
在python 3.6的cPython实现中:
{ "foo": 1, "bar": 2, "fiddle": { "bar": 2, "foo": 1 } }
真正的好消息是,这已经成为python 3.7的语言规范(而不是cPython 3.6+的实现细节):https://mail.python.org/pipermail/python-dev/2017-December/151283.html
所以现在问题的答案是:升级到python 3.6!:)