Могу ли я получить JSON для загрузки в OrderedDict? - PullRequest
399 голосов
/ 03 августа 2011

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

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

Если нет, есть ли какое-то решение?

Ответы [ 6 ]

564 голосов
/ 03 августа 2011

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

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

Вы можете передать этот параметр в json.loads (если вам не нужен экземпляр Decoder для других целей), например так:

>>> 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)
124 голосов
/ 03 августа 2011

Простая версия для 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)
28 голосов
/ 19 декабря 2017

Хорошие новости!Начиная с версии 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!:)

7 голосов
/ 03 августа 2011

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

5 голосов
/ 24 февраля 2015

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

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

3 голосов
/ 16 ноября 2017

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