serialize dumps dict create array python json integer hex

dumps - python object to json



Cómo imprimir enteros como cadenas hexagonales utilizando json.dumps() en Python (6)

Actualmente estoy usando el siguiente código para imprimir una gran estructura de datos

print(json.dumps(data, indent=4))

Me gustaría ver todos los enteros que se imprimen en hexadecimal en lugar de decimal. ¿Es eso posible? Parece que no hay forma de anular el codificador existente para enteros. Solo puede proporcionar un valor predeterminado para los tipos que aún no maneja la clase JSONEncoder, pero no hay manera de anular la forma en que codifica los enteros.

Me di cuenta de que puedo anular el comportamiento de impresión de enteros por defecto utilizando sys.displayhook si estuviera ejecutando en la línea de comandos, pero no lo estoy.

Solo como referencia, la estructura de datos es una mezcla de dicts, listas, cadenas, ints, etc. Por eso fui con json.dumps () . La única otra forma en que puedo pensar es en analizarlo yo mismo y luego volvería a escribir el módulo json.

Actualización: Así que terminé implementándolo con funciones de serialización que simplemente imprimen una copia de la estructura de datos original con todos los tipos de enteros convertidos a cadenas hexagonales:

def odprint(self, hexify=False): """pretty print the ordered dictionary""" def hexify_list(data): _data = [] for i,v in enumerate(data): if isinstance(v, (int,long)): _data.insert(i,hex(v)) elif isinstance(v,list): _data.insert(i, hexify_list(v)) else: _data.insert(i, val) return _data def hexify_dict(data): _data = odict() for k,v in data.items(): if isinstance(v, (dict,odict)): _data[k] = hexify_dict(v) elif isinstance(v, (int, long)): _data[k] = hex(v) elif isinstance(v,list): _data[k] = hexify_list(v) else: _data[k] = v return _data if hexify: print(json.dumps(hexify_dict(self), indent=4)) else: print(json.dumps(self, indent=4))

Gracias por la ayuda. Me doy cuenta de que termino siendo un odict de un dict estándar, pero es solo para imprimir, así que está bien para lo que necesito.


Dirty hack para Python 2.7, no recomendaría usarlo:

import __builtin__ _orig_str = __builtin__.str def my_str(obj): if isinstance(obj, (int, long)): return hex(obj) return _orig_str(obj) __builtin__.str = my_str import json data = {''a'': [1,2,3], ''b'': 4, ''c'': 16**20} print(json.dumps(data, indent=4))

Salida:

{ "a": [ 0x1, 0x2, 0x3 ], "c": 0x100000000000000000000L, "b": 0x4 }

En Python 3 el módulo __builtin__ ahora está builtins , pero no puedo probarlo (ideone.com falla con ImportError: libz.so.1 ...)


Los formatos octales y hexadecimales no son compatibles con JSON .

Podría usar YAML lugar.

>>> import json, yaml >>> class hexint(int): ... def __str__(self): ... return hex(self) ... >>> json.dumps({"a": hexint(255)}) ''{"a": 0xff}'' >>> yaml.load(_) {''a'': 255}

O sin envolver enteros:

import yaml def hexint_presenter(dumper, data): return dumper.represent_int(hex(data)) yaml.add_representer(int, hexint_presenter) print yaml.dump({"a": 255}), # -> {a: 0xff} assert yaml.load(''{a: 0xff}'') == {"a": 255}


No puede anular el codificador existente para enteros ... pero podría haber otra forma de obtener lo que desea. ¿Qué tal algo así?

import json import re data = {''test'': 33, ''this'': 99, ''something bigger'':[1,2,3, {''a'':44}]} s = json.dumps(data, indent=4) print(re.sub(''(/d+)'', lambda i: hex(int(i.group(0))),s))

Resultados en:

{ "test": 0x21, "this": 0x63, "something bigger": [ 0x1, 0x2, 0x3, { "a": 0x2c } ] }

Nota: Esto no es especialmente "robusto" (falla en los números integrados en cadenas, flotadores, etc.), pero podría ser lo suficientemente bueno para lo que desee (también podría mejorar la expresión regular aquí para que funcione en algunos casos más) )


Un posible enfoque es tener una función de serialize , que produce una copia de su diccionario sobre la marcha y utiliza el módulo json estándar para volcar la cadena. Una implementación preliminar se ve así:

import json def serialize(data): _data = {} for k, v in data.items(): if isinstance(v, int): _data[k] = hex(v) else: _data[k] = v return json.dumps(_data, indent=4) if __name__ == "__main__": data = {"a":1, "b":2.0, "c":3} print serialize(data)

salida:

{ "a": "0x1", "c": "0x3", "b": 2.0 }

Tenga en cuenta que esta implementación preliminar no funciona con listas, pero esto se puede cambiar fácilmente.

Algunos pueden afirmar que el enfoque requiere mucha memoria porque crea una copia de los datos originales. Este puede ser el caso, pero si su estructura de datos es tan grande, entonces quizás debería (a) no usar JSON, o (b) crear una copia del módulo JSON en su directorio de trabajo y adaptarlo a sus necesidades.

Aclamaciones.


Siempre puedes volver a rastrear el json, donde tienes cierto control sobre el análisis int, para que puedas anular el int repr:

class hexint(int): def __repr__(self): return "0x%x" % self json.loads(json.dumps(data), parse_int=hexint)

Y usando los data como en la respuesta de Gerrat, la salida es:

{u''test'': 0x21, u''this'': 0x63, u''something bigger'': [0x1, 0x2, 0x3, {u''a'': 0x2c}]}


Un trazador de líneas

Si no le molestan sus cadenas hexagonales citadas, use este unipersonal:

print(json.dumps(eval(str(json.loads(json.dumps(data), parse_int=lambda i:hex(int(i))))), indent=4))

Salida (usando los data de Gerrat nuevamente):

{ "test": "0x21", "this": "0x63", "something bigger": [ "0x1", "0x2", "0x3", { "a": "0x2c" } ] }

Esta es una respuesta mejor que mi publicación anterior ya que he tratado de obtener un resultado bastante impreso.