Могу ли я загрузить 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- декабрь /151283.html

Итак, ответ на ваш вопрос теперь становится: upgrade to python 3.6! :)

Ответ 4

Вы всегда можете выписать список ключей в дополнение к сбросу dict, а затем восстановить OrderedDict путем итерации по списку?

Ответ 5

Помимо сброса упорядоченного списка ключей наряду с словарем, другое низкотехнологичное решение, которое имеет преимущество явного, состоит в том, чтобы сбрасывать (упорядоченный) список пар ключ-значение ordered_dict.items(); загрузка - это простой OrderedDict(<list of key-value pairs>). Это обрабатывает упорядоченный словарь, несмотря на то, что JSON не имеет этого понятия (словари JSON не имеют порядка).

Действительно приятно воспользоваться тем, что json выгружает OrderedDict в правильном порядке. Однако, как правило, излишне тяжело и необязательно иметь смысл читать все словари JSON как OrderedDict (через аргумент object_pairs_hook), поэтому явное преобразование только словарей, которые должны быть упорядочены, тоже имеет смысл.

Ответ 6

Обычно используемая команда загрузки будет работать, если вы укажете параметр 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)

Ответ 7

Эта библиотека superjson может сделать это. И вы можете легко настроить json сериализатор для вашего собственного объекта Python, следуя этой инструкции https://superjson.readthedocs.io/index.html#extend.

Общая концепция:

ваш код должен найти правильный метод сериализации/десериализации на основе объекта python. Обычно полное имя класса является хорошим идентификатором.

И тогда ваш метод ser/deser должен быть в состоянии преобразовать ваш объект в обычный сериализуемый объект Json, комбинацию универсального типа python, dict, list, string, int, float. И реализуй свой метод дезер обратно.