Могу ли я загрузить 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. И реализуй свой метод дезер обратно.