He descubierto 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 preservar la clave como int, sin necesidad de analizar la cadena al volcar y cargar? Creo que sería posible usar los ganchos provistos por el módulo json, pero nuevamente esto aún requiere análisis. ¿Hay alguna discusión que haya pasado por alto? salud, chaz
Subpregunta: Gracias por las respuestas. Viendo que json funciona como temía, ¿hay una manera fácil de transmitir el tipo de clave al analizar la salida de los volcados? También debo tener en cuenta que el código que realiza el volcado y el código que descarga el objeto json de un servidor y lo carga, ambos están escritos por mí.
Respuestas:
Esta es una de esas sutiles diferencias entre varias colecciones de mapas que pueden morderte. JSON trata las claves como cadenas; Python admite teclas distintas que difieren solo en tipo.
En Python (y aparentemente en Lua) las claves de un mapeo (diccionario o tabla, respectivamente) son referencias de objetos. En Python deben ser tipos inmutables, o deben ser objetos que implementen un
__hash__
método. (Los documentos de Lua sugieren que usa automáticamente la ID del objeto como un hash / clave incluso para objetos mutables y se basa en el internamiento de cadenas para garantizar que las cadenas equivalentes se asignen a los mismos objetos).En Perl, Javascript, awk y muchos otros idiomas, las claves para hash, matrices asociativas o como se llamen para el idioma dado son cadenas (o "escalares" en Perl). En perl
$foo{1}, $foo{1.0}, and $foo{"1"}
están todas las referencias a la misma asignación en%foo
--- se evalúa la clave como escalar!JSON comenzó como una tecnología de serialización 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 ambos extremos de su serialización van a ser Python, entonces sería mejor usar encurtidos. Si realmente necesita convertirlos de JSON a objetos nativos de Python, supongo que tiene un par de opciones. Primero, puede intentar (
try: ... except: ...
) convertir cualquier clave en un número en caso de un error en la búsqueda del diccionario. Alternativamente, si agrega código al otro extremo (el serializador o generador de estos datos JSON), puede hacer que realice una serialización JSON en cada uno de los valores clave, proporcionándolos como una lista de claves. (Luego, su código 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).fuente
No, no existe una clave numérica en JavaScript. Todas las propiedades del objeto se convierten en String.
Esto puede conducir a algunos comportamientos curiosos:
Los objetos JavaScript no son realmente correlaciones adecuadas, como lo entenderías en lenguajes como Python, y el uso de teclas que no son cadenas da como resultado una rareza. Es por eso que JSON siempre escribe claves explícitamente como cadenas, incluso donde no parece necesario.
fuente
999999999999999999999
convierte a'999999999999999999999'
?Number
tipo es un valor de coma flotante doble IEEE 754 : obtienes 53 bits de mantisa, por lo que puedes almacenar hasta 2⁵³ (9007199254740992) con precisión entera; más allá de eso, los enteros se redondearán a otros valores (por lo tanto, 9007199254740993 === 9007199254740992). 999999999999999999999 se redondea a 1000000000000000000000, para lo cual latoString
representación predeterminada es1e+21
.Alternativamente, también puede intentar convertir el diccionario a una lista de formato [(k1, v1), (k2, v2)] mientras lo codifica usando json, y volverlo a convertir al diccionario después de volver a decodificarlo.
Creo que esto necesitará más trabajo, como tener algún tipo de indicador para identificar qué parámetros se convertirán al diccionario después de descodificarlo de json.fuente
Respondiendo su pregunta:
Se puede lograr usando
json.loads(jsonDict, object_hook=jsonKeys2int)
Esta función también funcionará para dictados anidados y utiliza una comprensión dict.
Si también desea emitir los valores, use:
Que prueba la instancia de los valores y los convierte solo si son objetos de cadenas (unicode para ser exactos).
Ambas funciones asumen que las claves (y los valores) son enteros.
Gracias a:
¿Cómo usar if / else en un diccionario de comprensión?
Convertir una clave de cadena a int en un diccionario
fuente
Me ha picado el mismo problema. Como otros han señalado, 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 sugeriría encurtidos. 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 lo hace).
fuente
Convierta el diccionario en cadena mediante el uso
str(dict)
y luego vuelva a convertirlo en dict haciendo esto:fuente
¡Aquí está mi solución! Solía
object_hook
, es útil cuando has anidadojson
Solo hay filtro para analizar la clave json a int. También puede usar el
int(v) if v.lstrip('-').isdigit() else v
filtro para el valor json.fuente
Hice una extensión muy simple de la respuesta de Murmel que creo que funcionará en un diccionario bastante arbitrario (incluido el anidado) suponiendo que JSON pueda descartarlo en primer lugar. Cualquier clave que se pueda interpretar como enteros se convertirá en int. Sin duda, esto no es muy eficiente, pero funciona para mis propósitos de almacenar y cargar desde cadenas json.
Suponiendo que todas las claves en el dict original son enteros si se pueden convertir a int, entonces esto devolverá el diccionario original después de almacenarlo como un json. p.ej
fuente
Puedes escribir tu
json.dumps
mismo, aquí hay un ejemplo de djson : encoder.py . Puedes usarlo así:fuente