Модуль JSON Python, преобразует ключи словаря int в строки



Я обнаружил, что когда выполняется следующее, модуль JSON python (включенный с 2.6) преобразует ключи словаря int в строки.



>>> import json
>>> releases = {1: "foo-v0.1"}
>>> json.dumps(releases)
'{"1": "foo-v0.1"}'


есть ли простой способ сохранить ключ как int, без необходимости разбирать строку на дамп и загрузку.
Я считаю, что было бы возможно использовать крючки, предоставляемые модулем json, но опять же это все еще требует разбора.
Возможно, есть аргумент, который я пропустил?
ура, Чаз



подвопрос:
Спасибо за ответы. Видя, как JSON работает, как я боялся, есть ли простой способ передать тип ключа, возможно, анализируя вывод дампов?
Также я должен отметить, что код, выполняющий демпинг, и код, загружающий объект json с сервера и загружающий его, написаны мной.

763   7  

7 ответов:

Это одно из тех тонких различий между различными коллекциями карт, которые могут укусить вас.

в Python (и, по-видимому, в Lua) ключи к отображению (словарь или таблица, соответственно) являются ссылками на объекты. В Python они должны быть неизменяемыми типами, или они должны быть объектами, которые реализуют a __hash__ метод. (Документы Lua предполагают, что он автоматически использует идентификатор объекта в качестве хэша / ключа даже для изменяемых объектов и полагается на интернирование строк, чтобы гарантировать, что эквивалент строки сопоставляются с теми же объектами).

в Perl, Javascript, awk и многих других языках ключи для хэшей, ассоциативных массивов или того, что они называются для данного языка, являются строками (или "скалярами" в Perl). В perl $foo{1}, $foo{1.0}, and $foo{"1"} все ссылки на одно и то же отображение в %foo --- ключ оценка как скаляр!

JSON запускается как технология сериализации Javascript. (JSON означает [J] ava [S]cript [o]bject [n]otation.) Естественно это реализует семантику для его обозначения отображения, которые согласуются с его семантикой отображения.

если оба конца вашей сериализации будут Python, то вам будет лучше использовать соленые огурцы. Если вам действительно нужно преобразовать их обратно из JSON в собственные объекты Python, я думаю, у вас есть несколько вариантов. Сначала вы можете попробовать (try: ... except: ...) для преобразования любого ключа в число в случае сбоя поиска словаря. Кроме того, если вы добавляете код на другой конец (the сериализатор или генератор этих данных JSON), то вы могли бы выполнить сериализацию JSON для каждого из ключевых значений --- предоставление их в виде списка ключей. (Тогда ваш код Python сначала перебрать список ключей, инстанцирование/десериализации их в родные объекты Python ... и затем использовать их для доступа к значениям из карт).

нет, в JavaScript нет такой вещи, как цифровой ключ. Все свойства объекта преобразуются в строку.

var a= {1: 'a'};
for (k in a)
    alert(typeof k); // 'string'

Это может привести к некоторым любопытным поведениям:

a[999999999999999999999]= 'a'; // this even works on Array
alert(a[1000000000000000000000]); // 'a'
alert(a['999999999999999999999']); // fail
alert(a['1e+21']); // 'a'

объекты JavaScript на самом деле не являются правильными отображениями, как вы понимаете это на таких языках, как Python, и использование ключей, которые не являются строковыми, приводит к странности. Вот почему JSON всегда явно записывает ключи как строки, даже там, где это не кажется необходимым.

в качестве альтернативы вы также можете попробовать преобразовать словарь в список формата [(k1,v1),(k2,v2)] при кодировании его с помощью json и преобразовании его обратно в словарь после его декодирования.


>>>> import json
>>>> json.dumps(releases.items())
    '[[1, "foo-v0.1"]]'
>>>> releases = {1: "foo-v0.1"}
>>>> releases == dict(json.loads(json.dumps(releases.items())))
     True
Я считаю, что для этого потребуется еще немного работы, например, иметь какой-то флаг, чтобы определить, какие все параметры должны быть преобразованы в словарь после декодирования его из json.

меня укусила та же проблема. Как указывали другие, в JSON ключи сопоставления должны быть строками. Вы можете сделать одну из двух вещей. Вы можете использовать менее строгую библиотеку JSON, например demjson, что позволяет целочисленные строки. Если никакие другие программы (или никакие другие на других языках) не будут читать его, то вы должны быть в порядке. Или вы можете использовать другой язык сериализации. Я бы не советовал мариновать. Это трудно читать, и это не предназначен, чтобы быть безопасный. Вместо этого я бы предложил YAML, который является (почти) надмножеством JSON и допускает целочисленные ключи. (По крайней мере PyYAML делает.)

отвечая на ваш подзапрос:

Это может быть достигнуто с помощью json.loads(jsonDict, object_hook=jsonKeys2int)

def jsonKeys2int(x):
    if isinstance(x, dict):
            return {int(k):v for k,v in x.items()}
    return x

эта функция также будет работать для вложенных диктов и использует понимание диктанта.

Если вы хотите, чтобы привести значения тоже, используйте:

def jsonKV2int(x):
    if isinstance(x, dict):
            return {int(k):(int(v) if isinstance(v, unicode) else v) for k,v in x.items()}
    return x

который проверяет экземпляр значений и приводит их только в том случае, если они являются объектами strings (unicode, чтобы быть точным).

обе функции предполагают, что ключи (и значения) являются целыми числами.

спасибо к:

как использовать if / else в понимании словаря?

преобразование строкового ключа в int в словаре

преобразовать словарь в строку с помощью str(dict) а затем преобразовать его обратно в dict, сделав это:

import ast
ast.literal_eval(string)

можно писать json.dumps самостоятельно, вот пример из djson: encoder.py. Вы можете использовать его следующим образом:

assert dumps({1: "abc"}) == '{1: "abc"}'

Comments

    Ничего не найдено.