Вопрос-Ответ

Can I get JSON to load into an OrderedDict?

Могу ли я заставить JSON загружаться в OrderedDict?

Хорошо, я могу использовать OrderedDict в json.dump. То есть OrderedDict можно использовать как входные данные для JSON.

Но можно ли его использовать как выходные данные? Если да, то как? В моем случае я хотел бы load в OrderedDict, чтобы я мог сохранить порядок ключей в файле.

Если нет, есть ли какой-нибудь обходной путь?

Переведено автоматически
Ответ 1

Да, вы можете. Указав object_pairs_hook аргумент для JSONDecoder. Фактически, это точный пример, приведенный в документации.

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

Вы можете передать этот параметр в 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 выполняется таким же образом:

>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)
Ответ 2

Простая версия для 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)
Ответ 3

Отличные новости! Начиная с версии 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
}

В реализации CPython на python 3.6:

{
"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! :)

Ответ 4

Обычно используемая команда load будет работать, если вы укажете параметр object_pairs_hook:

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