关于python:我可以让json加载到ordereddict中吗?

Can I get JSON to load into an OrderedDict?

好的,我可以在json.dump中使用ordereddict。也就是说,ordereddict可以用作JSON的输入。

但它能被用作输出吗?如果是这样怎么办?在我的例子中,我想将cx1〔1〕转换成一个有序的ICT,这样我就可以将密钥的顺序保存在文件中。

如果没有,有什么解决办法吗?


是的,你可以。通过向jsondecoder指定object_pairs_hook参数。事实上,这是文档中给出的确切示例。

1
2
3
>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1,"bar": 2}')
OrderedDict([('foo', 1), ('bar', 2)])
>>>

您可以将此参数传递给json.loads(如果您不需要其他用途的解码器实例),如下所示:

1
2
3
4
5
6
7
8
9
>>> 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的方式相同:

1
>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)


python 2.7的简单版本+

1
my_ordered_dict = json.loads(json_str, object_pairs_hook=collections.OrderedDict)

或者对于python 2.4到2.6

1
2
3
4
import simplejson as json
import ordereddict

my_ordered_dict = json.loads(json_str, object_pairs_hook=ordereddict.OrderedDict)


好消息!自3.6版以来,cpython实现保留了字典的插入顺序(https://mail.python.org/pipermail/python dev/2016-09/146327.html)。这意味着JSON库现在默认为订单保留。观察python 3.5和3.6之间的行为差异。代码:

1
2
3
import json
data = json.loads('{"foo":1,"bar":2,"fiddle":{"bar":2,"foo":1}}')
print(json.dumps(data, indent=4))

在PY3.5中,结果顺序未定义:

1
2
3
4
5
6
7
8
{
   "fiddle": {
       "bar": 2,
       "foo": 1
    },
   "bar": 2,
   "foo": 1
}

在python 3.6的cpython实现中:

1
2
3
4
5
6
7
8
{
   "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!:)


除了转储dict之外,您还可以编写键列表,然后通过遍历该列表来重新构造OrderedDict


除了在字典旁边转储键的有序列表外,另一个技术含量低的解决方案,其优点是可以明确地转储键值对ordered_dict.items()的(有序)列表;加载是一个简单的OrderedDict()。尽管JSON没有这个概念(JSON字典没有顺序),但它处理有序字典。

利用json以正确的顺序转储所订购的ICT这一事实确实很好。但是,一般来说,将所有JSON字典作为一个有序的ICT(通过object_pairs_hook参数)读取是不必要的,也不一定有意义的,因此仅对必须排序的字典进行显式转换也是有意义的。


如果指定对象对挂钩参数,通常使用的加载命令将工作:

1
2
3
4
import json
from  collections import OrderedDict
with open('foo.json', 'r') as fp:
    metrics_types = json.load(fp, object_pairs_hook=OrderedDict)