query - El módulo json de Python convierte las teclas del diccionario int en cadenas
python json to object (7)
He encontrado que cuando se ejecuta lo siguiente, el módulo json de python (incluido desde 2.6) convierte las claves del diccionario int en cadenas.
>>> import json
>>> releases = {1: "foo-v0.1"}
>>> json.dumps(releases)
''{"1": "foo-v0.1"}''
¿Hay alguna manera fácil de conservar la clave como un int, sin necesidad de analizar la cadena en volcar y cargar. Creo que sería posible usar los ganchos proporcionados por el módulo json, pero de nuevo esto todavía requiere un análisis sintáctico. ¿Hay posiblemente un argumento que he pasado por alto? aplausos, chaz
Subpregunta: Gracias por las respuestas. Al ver que json funciona como me temía, ¿hay alguna manera fácil de transmitir el tipo de clave quizás analizando la salida de los volcados? También debo señalar que el código que realiza el dumping y el código que descarga el objeto json de un servidor y que lo está cargando, ambos los he escrito yo.
Alternativamente, también puede intentar convertir diccionario a una lista de formato [(k1, v1), (k2, v2)] mientras lo codifica usando json, y convertirlo de nuevo en diccionario después de decodificarlo.
>>>> import json
>>>> json.dumps(releases.items())
''[[1, "foo-v0.1"]]''
>>>> releases = {1: "foo-v0.1"}
>>>> releases == dict(json.loads(json.dumps(releases.items())))
True
Creo que esto requerirá algo más de trabajo, como tener algún tipo de bandera para identificar qué todos los parámetros se convertirán al diccionario después de decodificarlo desde json.
Convierta el diccionario en cadena utilizando str(dict)
y luego conviértalo de nuevo a dicto haciendo esto:
import ast
ast.literal_eval(string)
Esta es una de esas diferencias sutiles entre varias colecciones de mapas que pueden morderte.
En Python (y aparentemente en Lua) las claves para un mapeo (diccionario o tabla, respectivamente) son referencias de objeto. En Python deben ser tipos inmutables, o deben ser objetos que implementen un método __hash__
. (Los documentos de Lua sugieren que utiliza automáticamente la identificación del objeto como una clave / hash incluso para objetos mutables y depende del interrogatorio de cadenas para asegurarse de que las cadenas equivalentes se correlacionen con los mismos objetos).
En Perl, Javascript, awk y muchos otros lenguajes, las claves para hashes, matrices asociativas o lo que sea que se les llame para el lenguaje dado, son cadenas (o "escalares" en Perl). En perl $foo{1}, $foo{1.0}, and $foo{"1"}
son todas referencias a la misma asignación en %foo
--- ¡la clave se evalúa como escalar!
JSON comenzó como una tecnología de serialización de Javascript. (JSON significa [J] ava [S] cript [o] bject [n] otation.) Naturalmente implementa semántica para su notación de mapeo que es consistente con su semántica de mapeo.
Si los dos extremos de su serialización van a ser Python, entonces sería mejor que use los encurtidos. Si realmente necesita convertirlos de JSON en objetos nativos de Python, supongo que tiene un par de opciones. Primero, podría intentar ( try: ... except: ...
) convertir cualquier clave en un número en caso de que falle la búsqueda del diccionario. Alternativamente, si agrega código al otro extremo (el serializador o generador de estos datos JSON), entonces podría hacer que realice una serialización JSON en cada uno de los valores clave, proporcionándolos como una lista de claves. (Entonces su código de Python primero iteraría sobre la lista de claves, instanciando / deserializándolas en objetos nativos de Python ... y luego las usaría para acceder a los valores fuera de la asignación).
Me ha picado el mismo problema. Como han señalado otros, en JSON, las claves de mapeo deben ser cadenas. Puedes hacer una de las dos cosas. Puede usar una biblioteca JSON menos estricta, como demjson , que permite cadenas enteras. Si ningún otro programa (o ningún otro en otros idiomas) lo va a leer, entonces debería estar bien. O puede usar un lenguaje de serialización diferente. No recomendaría Pickle. Es difícil de leer y no está diseñado para ser seguro . En cambio, sugeriría YAML, que es (casi) un superconjunto de JSON, y permite claves enteras. (Al menos PyYAML sí)
No, no existe una clave numérica en JavaScript. Todas las propiedades del objeto se convierten a String.
var a= {1: ''a''};
for (k in a)
alert(typeof k); // ''string''
Esto puede llevar a comportamientos aparentemente curiosos:
a[999999999999999999999]= ''a''; // this even works on Array
alert(a[1000000000000000000000]); // ''a''
alert(a[''999999999999999999999'']); // fail
alert(a[''1e+21'']); // ''a''
Los objetos de JavaScript no son realmente asignaciones correctas como lo entenderías en lenguajes como Python, y el uso de claves que no son cadenas resulta en rareza. Esta es la razón por la que JSON siempre escribe claves explícitamente como cadenas, incluso cuando no parece necesario.
Puede escribir sus json.dumps
usted mismo, aquí hay un ejemplo de djson : encoder.py . Puedes usarlo así:
assert dumps({1: "abc"}) == ''{1: "abc"}''
Respondiendo tu pregunta:
Se puede lograr utilizando json.loads(jsonDict, object_hook=jsonKeys2str)
def jsonKeys2str(x):
if isinstance(x, dict):
return {int(k):v for k,v in x.items()}
return x
Esta función también funcionará para dictados anidados y usa una comprensión dict.
Si también quieres lanzar los valores, utiliza:
def jsonKV2str(x):
if isinstance(x, dict):
return {int(k):(int(v) if isinstance(v, unicode) else v) for k,v in x.items()}
return x
Que prueba la instancia de los valores y los lanza solo si son objetos de cadenas (Unicode para ser exactos).
Ambas funciones asumen que las claves (y los valores) son enteros.
Gracias a: