type simple serialize not dumps python json serializable

serialize - simple json python



Objetos serializables Python json. (5)

class gpagelet: """ Holds 1) the pagelet xpath, which is a string 2) the list of pagelet shingles, list """ def __init__(self, parent): if not isinstance( parent, gwebpage): raise Exception("Parent must be an instance of gwebpage") self.parent = parent # This must be a gwebpage instance self.xpath = None # String self.visibleShingles = [] # list of tuples self.invisibleShingles = [] # list of tuples self.urls = [] # list of string class gwebpage: """ Holds all the datastructure after the results have been parsed holds: 1) lists of gpagelets 2) loc, string, location of the file that represents it """ def __init__(self, url): self.url = url # Str self.netloc = False # Str self.gpagelets = [] # gpagelets instance self.page_key = "" # str

¿Hay alguna manera de hacer que mi clase json sea serializable? Lo que me preocupa es la referencia recursiva.


Escriba su propio codificador y decodificador, que puede ser muy simple como return __dict__

Por ejemplo, aquí hay un codificador para volcar la estructura de árbol totalmente recursiva, puedes mejorarla o usarla como es para tu propio propósito.

import json class Tree(object): def __init__(self, name, childTrees=None): self.name = name if childTrees is None: childTrees = [] self.childTrees = childTrees class MyEncoder(json.JSONEncoder): def default(self, obj): if not isinstance(obj, Tree): return super(MyEncoder, self).default(obj) return obj.__dict__ c1 = Tree("c1") c2 = Tree("c2") t = Tree("t",[c1,c2]) print json.dumps(t, cls=MyEncoder)

se imprime

{"childTrees": [{"childTrees": [], "name": "c1"}, {"childTrees": [], "name": "c2"}], "name": "t"}

de manera similar, puede escribir un decodificador, pero de alguna manera tendrá que identificar si es su objeto o no, por lo que puede poner un tipo también si es necesario.


Implementé un método de todict muy simple con la ayuda de https://.com/a/11637457/1766716

  • Iterar sobre propiedades que no comienzan con __
  • Eliminar metodos
  • Eliminar algunas propiedades manualmente, lo que no es necesario (en mi caso, proveniente de sqlalcemy)

Y usé getattr para construir el diccionario.

class User(Base): id = Column(Integer, primary_key=True) firstname = Column(String(50)) lastname = Column(String(50)) password = Column(String(20)) def props(self): return filter( lambda a: not a.startswith(''__'') and a not in [''_decl_class_registry'', ''_sa_instance_state'', ''_sa_class_manager'', ''metadata''] and not callable(getattr(self, a)), dir(self)) def todict(self): return {k: self.__getattribute__(k) for k in self.props()}


Mi solución para esto fue ampliar la clase ''dict'' y realizar comprobaciones en torno a los atributos requeridos / permitidos al anular los métodos de inicio, actualización y configuración de la clase.

class StrictDict(dict): required=set() at_least_one_required=set() cannot_coexist=set() allowed=set() def __init__(self, iterable={}, **kwargs): super(StrictDict, self).__init__({}) keys = set(iterable.keys()).union(set(kwargs.keys())) if not keys.issuperset(self.required): msg = str(self.__class__.__name__) + " requires: " + str([str(key) for key in self.required]) raise AttributeError(msg) if len(list(self.at_least_one_required)) and len(list(keys.intersection(self.at_least_one_required))) < 1: msg = str(self.__class__.__name__) + " requires at least one: " + str([str(key) for key in self.at_least_one_required]) raise AttributeError(msg) for key, val in iterable.iteritems(): self.__setitem__(key, val) for key, val in kwargs.iteritems(): self.__setitem__(key, val) def update(self, E=None, **F): for key, val in E.iteritems(): self.__setitem__(key, val) for key, val in F.iteritems(): self.__setitem__(key, val) super(StrictDict, self).update({}) def __setitem__(self, key, value): all_allowed = self.allowed.union(self.required).union(self.at_least_one_required).union(self.cannot_coexist) if key not in list(all_allowed): msg = str(self.__class__.__name__) + " does not allow member ''" + key + "''" raise AttributeError(msg) if key in list(self.cannot_coexist): for item in list(self.cannot_coexist): if key != item and item in self.keys(): msg = str(self.__class__.__name__) + "does not allow members ''" + key + "'' and ''" + item + "'' to coexist''" raise AttributeError(msg) super(StrictDict, self).__setitem__(key, value)

Ejemplo de uso:

class JSONDoc(StrictDict): """ Class corresponding to JSON API top-level document structure http://jsonapi.org/format/#document-top-level """ at_least_one_required={''data'', ''errors'', ''meta''} allowed={"jsonapi", "links", "included"} cannot_coexist={"data", "errors"} def __setitem__(self, key, value): if key == "included" and "data" not in self.keys(): msg = str(self.__class__.__name__) + " does not allow ''included'' member if ''data'' member is not present" raise AttributeError(msg) super(JSONDoc, self).__setitem__(key, value) json_doc = JSONDoc( data={ "id": 5, "type": "movies" }, links={ "self": "http://url.com" } )


Respuesta indirecta: en lugar de usar JSON, puede usar YAML , que no tiene ningún problema en hacer lo que quiere. (JSON es esencialmente un subconjunto de YAML).

Ejemplo:

import yaml o1 = gwebpage("url") o2 = gpagelet(o1) o1.gpagelets = [o2] print yaml.dump(o1)

De hecho, YAML maneja bien las referencias cíclicas para ti.


jsonpickle para el jsonpickle !

(Solo tenía esta misma pregunta ... json pickle maneja los gráficos de objetos recursivos / anidados, así como los cortocircuitos para los gráficos de objetos cíclicos).