Estoy tratando de crear una cadena JSON representación de una instancia de una clase y tener dificultad. Digamos que la clase está construida como este:

class testclass:
    value1 = "a"
    value2 = "b"

Una llamada a la json.los vertederos se hace así:

t = testclass()
json.dumps(t)

Se está fallando y me dice que la testclass no es JSON serializable.

TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable

También he probado a utilizar el módulo pickle :

t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))

Y se da a la instancia de la clase de información, pero no serializado contenido de la instancia de la clase.

b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'

¿Qué estoy haciendo mal?

  • stackoverflow.com/questions/2343535/…
  • El uso de una línea, s = json.dumps(obj, default=lambda x: x.__dict__), para serializar el objeto de las variables de instancia (self.value1, self.value2, …). Es la más simple y la más sencilla. Se va a serializar el objeto anidado estructuras. El default función es llamada cuando cualquier objeto no es directamente serializable. También puede buscar en mi respuesta a continuación. He encontrado las respuestas populares innecesariamente complejo, que fueron probablemente cierto bastante tiempo atrás.
  • Su testclass no tiene __init__() método, por lo que todas las instancias comparten la misma dos atributos de la clase (value1 y value2) definido en la clase de instrucción. ¿Entiendes la diferencia entre una clase y un ejemplo de uno?
  • Hay una biblioteca de python para este github.com/jsonpickle/jsonpickle (comentarios ya que la respuesta es demasiado abajo en el hilo y no será accesible.)
InformationsquelleAutor ferhan | 2012-04-20

10 Comentarios

  1. 201

    El problema básico es que el JSON codificador json.dumps() sólo sabe cómo serializar un conjunto limitado de tipos de objeto por defecto, todos los tipos integrados. La lista aquí: https://docs.python.org/3.3/library/json.html#encoders-and-decoders

    Una buena solución sería crear una clase hereda de JSONEncoder y, a continuación, implementar el JSONEncoder.default() función, y asegúrese de que la función de emitir la correcta JSON para su clase.

    Una solución sencilla sería la llamada a la json.dumps() en el .__dict__ miembro de esa instancia. Que es un estándar de Python dict y si la clase es simple será JSON serializable.

    class Foo(object):
        def __init__(self):
            self.x = 1
            self.y = 2
    
    foo = Foo()
    s = json.dumps(foo) # raises TypeError with "is not JSON serializable"
    
    s = json.dumps(foo.__dict__) # s set to: {"x":1, "y":2}

    El enfoque anterior es que hablamos en este blog de publicación:

        Serializar arbitraria de objetos de Python para JSON usando __dict__

    • He intentado esto. El resultado final de una llamada a json.vertederos(t.__dict__) es sólo {}.
    • Eso es porque la clase no tiene un .__init__() método de la función, por lo que su instancia de la clase tiene un diccionario vacío. En otras palabras, {} es el resultado correcto para su código de ejemplo.
    • Gracias. Esto hace el truco. He añadido un simple init sin parámetros y llamando ahora el json.vertederos(t.__dict__) devuelve apropiada de los datos en el formato de: {«value2»: «345», «valor1»: «123»} yo había visto posts como este antes, no estaba seguro de si lo que necesitaba un serializador personalizado para los miembros, que necesitan init no se mencionó explícitamente o se me perdió. Gracias.
    • Este trabajo para una sola clase, pero no con clases de objetos
    • Verdadero. Si tienes un objeto que, por ejemplo, es que contiene varios objetos en una lista el error es todavía is not JSON serializable
    • así que, en ese caso, ¿cómo podría obtener el json de los múltiples objetos?
    • Alguien puede proporcionar una buena referencia para el enfoque de la herencia de JSONEncoder y, a continuación, la aplicación de la JSONEncoder.predeterminado() la función?
    • También, ¿qué debo hacer si tengo que obtener la representación JSON de no solo 1 objeto, sino una lista de los objetos?
    • el __dict__ enfoque, Funciona como un encanto, sólo el nombre de la clase se presenta anexa el nombre del atributo. Que en mi caso está bien. El Uso De Python3.5 en Mac

  2. 46

    Hay una manera en la que funciona muy bien para mí, que usted puede probar:

    json.dumps() puede tomar un parámetro opcional defecto donde puede especificar un serializador personalizado función de tipos desconocidos, que en mi caso se parece a

    def serialize(obj):
        """JSON serializer for objects not serializable by default json code"""
    
        if isinstance(obj, date):
            serial = obj.isoformat()
            return serial
    
        if isinstance(obj, time):
            serial = obj.isoformat()
            return serial
    
        return obj.__dict__

    Dos primeros ifs son la fecha y la hora de la serialización
    y luego hay un obj.__dict__ devuelto por cualquier otro objeto.

    la llamada final parece:

    json.dumps(myObj, default=serialize)

    Es especialmente bueno cuando se está serializando una colección y usted no quiere llamar __dict__ explícitamente para cada objeto. Aquí se hace automáticamente para usted.

    Hasta ahora funcionó tan bien para mí, a la espera de sus pensamientos.

    • Muchas gracias por esta respuesta, que me ha ayudado mucho.
    • Usted debe conseguir más puntos para esta respuesta 🙂 es muy bonito y elegante solución!!
    • Puedo obtener NameError: name 'serialize' is not defined. Algún consejo?
    • Muy bonito. Sólo para las clases que tienen ranuras: try: dict = obj.__dict__ except AttributeError: dict = {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)} return dict
  3. 36

    Puede especificar el default nombre del parámetro en la json.dumps() función:

    json.dumps(obj, default=lambda x: x.__dict__)

    Explicación:

    Forma de la documentación (2.7, 3.6):

    ``default(obj)`` is a function that should return a serializable version
    of obj or raise TypeError. The default simply raises TypeError.

    (Funciona en Python 2.7 y Python 3.x)

    Nota: En este caso es necesario instance variables y no class variables, como en el ejemplo de la pregunta que intenta hacer. (Estoy suponiendo que el autor de la pregunta significaba class instance a ser un objeto de una clase)

    Esto lo aprendí en la primera de @phihag la respuesta de aquí. Encontrado para ser el más simple y limpia para hacer el trabajo.

    • Esto funcionó para mí, sino porque de datetime.fecha de miembros de la he cambiado ligeramente: default=lambda x: getattr(x, '__dict__', str(x))
    • buen trabajo-alrededor; datetime.date es una implementación en C por lo tanto no tiene __dict__ atributo. En mi humilde opinión, para el bien de la uniformidad, datetime.date debe tener…
  4. 22

    Acabo de hacer:

    data=json.dumps(myobject.__dict__)

    Esta no es la respuesta completa, y si usted tiene algún tipo de complicado clase de objeto que sin duda no va a conseguir todo. Sin embargo, yo uso esto para algunos de mis objetos simples.

    Uno que funciona muy bien es la de las «opciones» de la clase que se obtiene de la OptionParser módulo.
    Aquí está junto con la petición JSON sí mismo.

      def executeJson(self, url, options):
            data=json.dumps(options.__dict__)
            if options.verbose:
                print data
            headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
            return requests.post(url, data, headers=headers)
    • Es posible que desee eliminar el auto, si usted no está utilizando esta dentro de una clase.
    • Que funcione bien, siempre y cuando el objeto no está compuesto de otros objetos.
  5. 4

    Aquí son dos funciones simples para la serialización de cualquier no sofisticado clases, nada de lujo, como se explicó antes.

    Yo lo uso para la configuración del tipo de cosas porque puedo agregar nuevos miembros a las clases con ningún código de ajustes.

    import json
    
    class SimpleClass:
        def __init__(self, a=None, b=None, c=None):
            self.a = a
            self.b = b
            self.c = c
    
    def serialize_json(instance=None, path=None):
        dt = {}
        dt.update(vars(instance))
    
        with open(path, "w") as file:
            json.dump(dt, file)
    
    def deserialize_json(cls=None, path=None):
        def read_json(_path):
            with open(_path, "r") as file:
                return json.load(file)
    
        data = read_json(path)
    
        instance = object.__new__(cls)
    
        for key, value in data.items():
            setattr(instance, key, value)
    
        return instance
    
    # Usage: Create class and serialize under Windows file system.
    write_settings = SimpleClass(a=1, b=2, c=3)
    serialize_json(write_settings, r"c:\temp\test.json")
    
    # Read back and rehydrate.
    read_settings = deserialize_json(SimpleClass, r"c:\temp\test.json")
    
    # results are the same.
    print(vars(write_settings))
    print(vars(read_settings))
    
    # output:
    # {'c': 3, 'b': 2, 'a': 1}
    # {'c': 3, 'b': 2, 'a': 1}
  6. 3

    JSON no es realmente significaba para serializar arbitraria de objetos de Python. Es ideal para serializar dict objetos, pero el pickle módulo es realmente lo que usted debe utilizar en general. Salida de pickle no es muy legible, pero debe unpickle bien. Si usted insiste en el uso de JSON, podría retirar la jsonpickle módulo, el cual es un interesante enfoque híbrido.

    https://github.com/jsonpickle/jsonpickle

    • El principal problema que yo veo con pickle es que es un Python-formato específico, mientras que JSON es una plataforma independiente de formato. JSON es especialmente útil si usted está escribiendo una aplicación web o un backend para algunas aplicaciones móviles. Dicho esto, gracias por señalar a jsonpickle.
    • No jsonpickle exportar a JSON, simplemente no es muy legible para los humanos?
  7. 2

    Creo que en lugar de la herencia, como se sugiere en aceptó responder, es mejor utilizar el polimorfismo. De lo contrario, usted tiene que tener un gran if else instrucción para personalizar la codificación de cada objeto. Que significa crear un genérico predeterminado codificador para JSON como:

    def jsonDefEncoder(obj):
       if hasattr(obj, 'jsonEnc'):
          return obj.jsonEnc()
       else: #some default behavior
          return obj.__dict__

    y, a continuación, tener un jsonEnc() función en cada clase que usted desea serializar. por ejemplo,

    class A(object):
       def __init__(self,lengthInFeet):
          self.lengthInFeet=lengthInFeet
       def jsonEnc(self):
          return {'lengthInMeters': lengthInFeet * 0.3 } # each foot is 0.3 meter

    A continuación, llamar json.dumps(classInstance,default=jsonDefEncoder)

  8. 1

    Hay algunas buenas respuestas sobre cómo empezar a hacerlo. Pero hay algunas cosas a tener en cuenta:

    • Lo que si la instancia está anidada dentro de una gran estructura de datos?
    • Lo que si también desea que el nombre de la clase?
    • Lo que si desea deserializar la instancia?
    • Lo que si usted está utilizando __slots__ en lugar de __dict__?
    • ¿Y si simplemente no quieres hacerlo tú mismo?

    json-trucos es una biblioteca (que he hecho y otros contribuyeron a) que ha sido capaz de hacer esto por un buen rato. Por ejemplo:

    class MyTestCls:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    cls_instance = MyTestCls(s='ub', dct={'7': 7})
    
    json = dumps(cls_instance, indent=4)
    instance = loads(json)

    Usted obtendrá su instancia. Aquí el json que se parece a esto:

    {
        "__instance_type__": [
            "json_tricks.test_class",
            "MyTestCls"
        ],
        "attributes": {
            "s": "ub",
            "dct": {
                "7": 7
            }
        }
    }

    Si te gusta hacer su propia solución, usted puede mirar en la fuente de json-tricks para no olvidar algunos casos especiales (como __slots__).

    También hace otros tipos, como arrays de numpy, datetimes, números complejos; también permite comentarios.

  9. 1

    Python3.x

    El mejor aproach podía llegar con mi conocimiento era este.

    Tenga en cuenta que este código tratar set() demasiado.

    Este enfoque es genérico sólo necesitan la extensión de la clase (en el segundo ejemplo).

    Tenga en cuenta que solo estoy haciendo a los archivos, pero es fácil de modificar la conducta a su gusto.

    Sin embargo, este es un CoDec.

    Con un poco más de trabajo que usted puede construir su clase en otras formas.
    Supongo que un constructor predeterminado a instancia de ella, luego actualizo la clase dict.

    import json
    import collections
    class JsonClassSerializable(json.JSONEncoder):
    REGISTERED_CLASS = {}
    def register(ctype):
    JsonClassSerializable.REGISTERED_CLASS[ctype.__name__] = ctype
    def default(self, obj):
    if isinstance(obj, collections.Set):
    return dict(_set_object=list(obj))
    if isinstance(obj, JsonClassSerializable):
    jclass = {}
    jclass["name"] = type(obj).__name__
    jclass["dict"] = obj.__dict__
    return dict(_class_object=jclass)
    else:
    return json.JSONEncoder.default(self, obj)
    def json_to_class(self, dct):
    if '_set_object' in dct:
    return set(dct['_set_object'])
    elif '_class_object' in dct:
    cclass = dct['_class_object']
    cclass_name = cclass["name"]
    if cclass_name not in self.REGISTERED_CLASS:
    raise RuntimeError(
    "Class {} not registered in JSON Parser"
    .format(cclass["name"])
    )
    instance = self.REGISTERED_CLASS[cclass_name]()
    instance.__dict__ = cclass["dict"]
    return instance
    return dct
    def encode_(self, file):
    with open(file, 'w') as outfile:
    json.dump(
    self.__dict__, outfile,
    cls=JsonClassSerializable,
    indent=4,
    sort_keys=True
    )
    def decode_(self, file):
    try:
    with open(file, 'r') as infile:
    self.__dict__ = json.load(
    infile,
    object_hook=self.json_to_class
    )
    except FileNotFoundError:
    print("Persistence load failed "
    "'{}' do not exists".format(file)
    )
    class C(JsonClassSerializable):
    def __init__(self):
    self.mill = "s"
    JsonClassSerializable.register(C)
    class B(JsonClassSerializable):
    def __init__(self):
    self.a = 1230
    self.c = C()
    JsonClassSerializable.register(B)
    class A(JsonClassSerializable):
    def __init__(self):
    self.a = 1
    self.b = {1, 2}
    self.c = B()
    JsonClassSerializable.register(A)
    A().encode_("test")
    b = A()
    b.decode_("test")
    print(b.a)
    print(b.b)
    print(b.c.a)

    Editar

    Con un poco más de investigación, he encontrado una manera de generalizar sin la necesidad de la SUPERCLASE método de registro de la llamada, el uso de un metaclass

    import json
    import collections
    REGISTERED_CLASS = {}
    class MetaSerializable(type):
    def __call__(cls, *args, **kwargs):
    if cls.__name__ not in REGISTERED_CLASS:
    REGISTERED_CLASS[cls.__name__] = cls
    return super(MetaSerializable, cls).__call__(*args, **kwargs)
    class JsonClassSerializable(json.JSONEncoder, metaclass=MetaSerializable):
    def default(self, obj):
    if isinstance(obj, collections.Set):
    return dict(_set_object=list(obj))
    if isinstance(obj, JsonClassSerializable):
    jclass = {}
    jclass["name"] = type(obj).__name__
    jclass["dict"] = obj.__dict__
    return dict(_class_object=jclass)
    else:
    return json.JSONEncoder.default(self, obj)
    def json_to_class(self, dct):
    if '_set_object' in dct:
    return set(dct['_set_object'])
    elif '_class_object' in dct:
    cclass = dct['_class_object']
    cclass_name = cclass["name"]
    if cclass_name not in REGISTERED_CLASS:
    raise RuntimeError(
    "Class {} not registered in JSON Parser"
    .format(cclass["name"])
    )
    instance = REGISTERED_CLASS[cclass_name]()
    instance.__dict__ = cclass["dict"]
    return instance
    return dct
    def encode_(self, file):
    with open(file, 'w') as outfile:
    json.dump(
    self.__dict__, outfile,
    cls=JsonClassSerializable,
    indent=4,
    sort_keys=True
    )
    def decode_(self, file):
    try:
    with open(file, 'r') as infile:
    self.__dict__ = json.load(
    infile,
    object_hook=self.json_to_class
    )
    except FileNotFoundError:
    print("Persistence load failed "
    "'{}' do not exists".format(file)
    )
    class C(JsonClassSerializable):
    def __init__(self):
    self.mill = "s"
    class B(JsonClassSerializable):
    def __init__(self):
    self.a = 1230
    self.c = C()
    class A(JsonClassSerializable):
    def __init__(self):
    self.a = 1
    self.b = {1, 2}
    self.c = B()
    A().encode_("test")
    b = A()
    b.decode_("test")
    print(b.a)
    # 1
    print(b.b)
    # {1, 2}
    print(b.c.a)
    # 1230
    print(b.c.c.mill)
    # s

Dejar respuesta

Please enter your comment!
Please enter your name here