not ejemplo dict create array python json serialization set

python - ejemplo - Cómo JSON serializar conjuntos?



python json to object (5)

Puede crear un codificador personalizado que devuelva una list cuando encuentre un set . Aquí hay un ejemplo:

>>> import json >>> class SetEncoder(json.JSONEncoder): ... def default(self, obj): ... if isinstance(obj, set): ... return list(obj) ... return json.JSONEncoder.default(self, obj) ... >>> json.dumps(set([1,2,3,4,5]), cls=SetEncoder) ''[1, 2, 3, 4, 5]''

Puede detectar otros tipos de esta manera también. Si necesita retener que la lista era en realidad un conjunto, podría usar una codificación personalizada. Algo como return {''type'':''set'', ''list'':list(obj)} podría funcionar.

Para los tipos anidados ilustrados, considere serializar esto:

>>> class Something(object): ... pass >>> json.dumps(set([1,2,3,4,5,Something()]), cls=SetEncoder)

Esto genera el siguiente error:

TypeError: <__main__.Something object at 0x1691c50> is not JSON serializable

Esto indica que el codificador tomará el resultado de la list devuelto y llamará recursivamente al serializador en sus hijos. Para agregar un serializador personalizado para varios tipos, puede hacer esto:

>>> class SetEncoder(json.JSONEncoder): ... def default(self, obj): ... if isinstance(obj, set): ... return list(obj) ... if isinstance(obj, Something): ... return ''CustomSomethingRepresentation'' ... return json.JSONEncoder.default(self, obj) ... >>> json.dumps(set([1,2,3,4,5,Something()]), cls=SetEncoder) ''[1, 2, 3, 4, 5, "CustomSomethingRepresentation"]''

Tengo un set Python que contiene objetos con métodos __hash__ y __eq__ para asegurarme de que no se incluyan duplicados en la colección.

Necesito codificar JSON este set resultados, pero pasar incluso un set vacío al método json.dumps genera un TypeError .

File "/usr/lib/python2.7/json/encoder.py", line 201, in encode chunks = self.iterencode(o, _one_shot=True) File "/usr/lib/python2.7/json/encoder.py", line 264, in iterencode return _iterencode(o, 0) File "/usr/lib/python2.7/json/encoder.py", line 178, in default raise TypeError(repr(o) + " is not JSON serializable") TypeError: set([]) is not JSON serializable

Sé que puedo crear una extensión para la clase json.JSONEncoder que tiene un método default personalizado, pero ni siquiera estoy seguro de por dónde empezar para convertirlo en el set . ¿Debo crear un diccionario a partir de los valores set en el método predeterminado y luego devolver la codificación sobre eso? Idealmente, me gustaría hacer que el método predeterminado sea capaz de manejar todos los tipos de datos que ahoga el codificador original (estoy usando Mongo como fuente de datos para que las fechas también parezcan generar este error).

Cualquier sugerencia en la dirección correcta sería apreciada.

EDITAR:

¡Gracias por la respuesta! Quizás debería haber sido más preciso.

Utilicé (y voté a favor) las respuestas aquí para evitar las limitaciones del set está traduciendo, pero también hay claves internas que también son un problema.

Los objetos en el set son objetos complejos que se traducen en __dict__ , pero también pueden contener valores para sus propiedades que podrían no ser elegibles para los tipos básicos en el codificador json.

Hay muchos tipos diferentes que entran en este set , y el hash básicamente calcula una identificación única para la entidad, pero en el verdadero espíritu de NoSQL no se sabe exactamente qué contiene el objeto hijo.

Un objeto puede contener un valor de fecha para starts , mientras que otro puede tener algún otro esquema que no incluya claves que contengan objetos "no primitivos".

Es por eso que la única solución que se me ocurrió fue extender el JSONEncoder para reemplazar el método default para activar diferentes casos, pero no estoy seguro de cómo hacerlo y la documentación es ambigua. En los objetos anidados, ¿el valor devuelto por el valor default ir por clave, o es solo una inclusión / descarte genérico que examina el objeto completo? ¿Cómo se adapta ese método a los valores anidados? He revisado las preguntas anteriores y parece que no puedo encontrar el mejor enfoque para la codificación de casos específicos (que desafortunadamente parece que voy a tener que hacer aquí).


Si solo necesita codificar conjuntos, no objetos Python generales, y desea que sea fácilmente legible para los humanos, se puede usar una versión simplificada de la respuesta de Raymond Hettinger:

import json import collections class JSONSetEncoder(json.JSONEncoder): """Use with json.dumps to allow Python sets to be encoded to JSON Example ------- import json data = dict(aset=set([1,2,3])) encoded = json.dumps(data, cls=JSONSetEncoder) decoded = json.loads(encoded, object_hook=json_as_python_set) assert data == decoded # Should assert successfully Any object that is matched by isinstance(obj, collections.Set) will be encoded, but the decoded value will always be a normal Python set. """ def default(self, obj): if isinstance(obj, collections.Set): return dict(_set_object=list(obj)) else: return json.JSONEncoder.default(self, obj) def json_as_python_set(dct): """Decode json {''_set_object'': [1,2,3]} to set([1,2,3]) Example ------- decoded = json.loads(encoded, object_hook=json_as_python_set) Also see :class:`JSONSetEncoder` """ if ''_set_object'' in dct: return set(dct[''_set_object'']) return dct


Solo diccionarios, listas y tipos de objetos primitivos (int, string, bool) están disponibles en JSON.


JSON notación JSON solo tiene un puñado de tipos de datos nativos (objetos, matrices, cadenas, números, booleanos y nulos), por lo que todo lo serializado en JSON debe expresarse como uno de estos tipos.

Como se muestra en los documentos del módulo json , una conversión JSONEncoder y JSONDecoder puede realizarla automáticamente, pero luego renunciaría a otra estructura que pueda necesitar (si convierte conjuntos en una lista, perderá la capacidad de recuperar archivos regulares). listas; si convierte conjuntos a un diccionario usando dict.fromkeys(s) entonces perderá la capacidad de recuperar diccionarios).

Una solución más sofisticada es construir un tipo personalizado que pueda coexistir con otros tipos JSON nativos. Esto le permite almacenar estructuras anidadas que incluyen listas, conjuntos, dictados, decimales, objetos de fecha y hora, etc.

from json import dumps, loads, JSONEncoder, JSONDecoder import pickle class PythonObjectEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, (list, dict, str, unicode, int, float, bool, type(None))): return JSONEncoder.default(self, obj) return {''_python_object'': pickle.dumps(obj)} def as_python_object(dct): if ''_python_object'' in dct: return pickle.loads(str(dct[''_python_object''])) return dct

Aquí hay una sesión de muestra que muestra que puede manejar listas, dictados y conjuntos:

>>> data = [1,2,3, set([''knights'', ''who'', ''say'', ''ni'']), {''key'':''value''}, Decimal(''3.14'')] >>> j = dumps(data, cls=PythonObjectEncoder) >>> loads(j, object_hook=as_python_object) [1, 2, 3, set([''knights'', ''say'', ''who'', ''ni'']), {u''key'': u''value''}, Decimal(''3.14'')]

Alternativamente, puede ser útil utilizar una técnica de serialización de propósito más general como YAML , Twisted Jelly o el módulo de pickle de Python. Cada uno de ellos admite un rango mucho mayor de tipos de datos.


Adapte la solución de Raymond Hettinger a python 3.

Esto es lo que ha cambiado:

  • unicode desapareció
  • actualizó la llamada al default los padres con super()
  • utilizando base64 para serializar el tipo de bytes en str (porque parece que los bytes en python 3 no se pueden convertir a JSON)

from decimal import Decimal from base64 import b64encode, b64decode from json import dumps, loads, JSONEncoder import pickle class PythonObjectEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, (list, dict, str, int, float, bool, type(None))): return super().default(obj) return {''_python_object'': b64encode(pickle.dumps(obj)).decode(''utf-8'')} def as_python_object(dct): if ''_python_object'' in dct: return pickle.loads(b64decode(dct[''_python_object''].encode(''utf-8''))) return dct data = [1,2,3, set([''knights'', ''who'', ''say'', ''ni'']), {''key'':''value''}, Decimal(''3.14'')] j = dumps(data, cls=PythonObjectEncoder) print(loads(j, object_hook=as_python_object)) # prints: [1, 2, 3, {''knights'', ''who'', ''say'', ''ni''}, {''key'': ''value''}, Decimal(''3.14'')]