Estoy tratando de crear una representación de cadena JSON de una instancia de clase y tengo dificultades. Digamos que la clase se construye así:
class testclass:
value1 = "a"
value2 = "b"
Una llamada a json.dumps se realiza así:
t = testclass()
json.dumps(t)
Está fallando y me dice que la clase de prueba no es serializable JSON.
TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable
También he intentado usar el módulo pickle:
t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))
Y proporciona información de instancia de clase pero no un contenido serializado de la instancia de clase.
b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'
¿Qué estoy haciendo mal?
python
json
serialization
pickle
ferhan
fuente
fuente
s = json.dumps(obj, default=lambda x: x.__dict__)
para las variables de instancia de objeto serialize (self.value1
,self.value2
, ...). Es la forma más sencilla y directa. Serializará estructuras de objetos anidados. Sedefault
llama a la función cuando cualquier objeto dado no es directamente serializable. También puedes ver mi respuesta a continuación. Encontré las respuestas populares innecesariamente complejas, que probablemente eran ciertas hace mucho tiempo.testclass
tiene__init__()
método, por lo que todas las instancias compartirán los mismos dos atributos de clase (value1
yvalue2
) definidos en la declaración de clase. ¿Entiendes la diferencia entre una clase y una instancia de una?Respuestas:
El problema básico es que el codificador JSON
json.dumps()
solo sabe cómo serializar un conjunto limitado de tipos de objetos de forma predeterminada, todos los tipos incorporados. Lista aquí: https://docs.python.org/3.3/library/json.html#encoders-and-decodersUna buena solución sería hacer que su clase herede
JSONEncoder
y luego implementeJSONEncoder.default()
función, y hacer que esa función emita el JSON correcto para su clase.Una solución simple sería llamar
json.dumps()
al.__dict__
miembro de esa instancia. Ese es un Python estándardict
y si su clase es simple, será serializable JSON.El enfoque anterior se analiza en esta publicación de blog:
Serializar objetos arbitrarios de Python a JSON usando __dict__
fuente
.__init__()
función de método, por lo que su instancia de clase tiene un diccionario vacío. En otras palabras,{}
es el resultado correcto para su código de ejemplo.is not JSON serializable
Hay una manera que funciona muy bien para mí que puedes probar:
json.dumps()
puede tomar un parámetro opcional predeterminado donde puede especificar una función de serializador personalizada para tipos desconocidos, que en mi caso se pareceLos primeros dos if son para la serialización de fecha y hora y luego hay un
obj.__dict__
devuelve cualquier otro objeto.la llamada final se ve así:
Es especialmente bueno cuando está serializando una colección y no desea llamar
__dict__
explícitamente a cada objeto. Aquí se hace automáticamente.Hasta ahora funcionó muy bien para mí, esperando sus pensamientos.
fuente
NameError: name 'serialize' is not defined
. ¿Algun consejo?try: dict = obj.__dict__ except AttributeError: dict = {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)} return dict
Puede especificar el
default
parámetro con nombre en lajson.dumps()
función:Explicación:
Forme los documentos ( 2.7 , 3.6 ):
(Funciona en Python 2.7 y Python 3.x)
Nota: En este caso, necesita
instance
variables y noclass
variables, como intenta hacer el ejemplo en la pregunta. (Supongo que el autor de la pregunta pretendeclass instance
ser un objeto de una clase)Aprendí esto primero de la respuesta de @ phihag aquí . Descubrí que es la forma más sencilla y limpia de hacer el trabajo.
fuente
default=lambda x: getattr(x, '__dict__', str(x))
datetime.date
es una implementación en C, por lo tanto, no tiene ningún__dict__
atributo. En mi humilde opinión por el bien de la uniformidad,datetime.date
debería tenerlo ...Solamente lo hago:
Esta no es la respuesta completa, y si tiene algún tipo de clase de objeto complicado, ciertamente no obtendrá todo. Sin embargo, uso esto para algunos de mis objetos simples.
Uno en el que funciona muy bien es la clase de "opciones" que obtienes del módulo OptionParser. Aquí está junto con la solicitud JSON en sí.
fuente
Usando jsonpickle
fuente
JSON no está realmente destinado a serializar objetos arbitrarios de Python. Es ideal para serializar
dict
objetos, pero elpickle
módulo es realmente lo que debería estar usando en general. La salida depickle
no es realmente legible para el ser humano, pero debería desaparecer bien. Si insiste en usar JSON, puede consultar eljsonpickle
módulo, que es un enfoque híbrido interesante.https://github.com/jsonpickle/jsonpickle
fuente
Aquí hay dos funciones simples para la serialización de cualquier clase no sofisticada, nada sofisticado como se explicó anteriormente.
Lo uso para el tipo de configuración porque puedo agregar nuevos miembros a las clases sin ajustes de código.
fuente
Hay algunas buenas respuestas sobre cómo comenzar a hacer esto. Pero hay algunas cosas a tener en cuenta:
__slots__
lugar de__dict__
?json-tricks es una biblioteca (que hice y a la que contribuyeron otros) que ha podido hacer esto durante bastante tiempo. Por ejemplo:
Recuperarás tu instancia. Aquí el json se ve así:
Si desea hacer su propia solución, puede mirar la fuente
json-tricks
para no olvidar algunos casos especiales (como__slots__
).También hace otros tipos como matrices numpy, fechas, números complejos; También permite comentarios.
fuente
Python3.x
El mejor enfoque que pude alcanzar con mi conocimiento fue este.
Tenga en cuenta que este código trata también a set ().
Este enfoque es genérico y solo necesita la extensión de clase (en el segundo ejemplo).
Tenga en cuenta que solo lo estoy haciendo a los archivos, pero es fácil modificar el comportamiento a su gusto.
Sin embargo, este es un CoDec.
Con un poco más de trabajo puedes construir tu clase de otras maneras. Asumo un constructor predeterminado para instanciarlo, luego actualizo la clase dict.
Editar
Con un poco más de investigación, encontré una manera de generalizar sin la necesidad de la llamada al método de registro SUPERCLASS , usando una metaclase
fuente
Creo que en lugar de la herencia como se sugiere en la respuesta aceptada, es mejor usar polimorfismo. De lo contrario, debe tener una gran instrucción if else para personalizar la codificación de cada objeto. Eso significa crear un codificador genérico predeterminado para JSON como:
y luego tiene una
jsonEnc()
función en cada clase que desea serializar. p.ejEntonces llamas
json.dumps(classInstance,default=jsonDefEncoder)
fuente