secret how from examples descargar con python json namedtuple

how - Serializando un Python nombrado tuple a json



twitter api secret key (6)

¿Cuál es la forma recomendada de serializar una namedtuple a json con los nombres de campo retenidos?

La serialización de un namedtuple a json da como resultado que solo los valores se serialicen y que los nombres de los campos se pierdan en la traducción. Me gustaría que los campos también se conserven cuando json-ized y por lo tanto hice lo siguiente:

class foobar(namedtuple(''f'', ''foo, bar'')): __slots__ = () def __iter__(self): yield self._asdict()

Lo anterior se serializa a json como espero y se comporta como namedtuple en otros lugares que uso (acceso a atributos, etc.), excepto con resultados similares a los de una tupla al iterarlo (lo cual está bien para mi caso de uso).

¿Cuál es la "forma correcta" de convertir a json con los nombres de campo retenidos?


Convierte de forma recursiva los datos nombradosTuple a json.

print(m1) ## Message(id=2, agent=Agent(id=1, first_name=''asd'', last_name=''asd'', mail=''[email protected]''), customer=Customer(id=1, first_name=''asd'', last_name=''asd'', mail=''[email protected]'', phone_number=123123), type=''image'', content=''text'', media_url=''h.com'', la=123123, ls=4512313) def reqursive_to_json(obj): _json = {} if isinstance(obj, tuple): datas = obj._asdict() for data in datas: if isinstance(datas[data], tuple): _json[data] = (reqursive_to_json(datas[data])) else: print(datas[data]) _json[data] = (datas[data]) return _json data = reqursive_to_json(m1) print(data) {''agent'': {''first_name'': ''asd'', ''last_name'': ''asd'', ''mail'': ''[email protected]'', ''id'': 1}, ''content'': ''text'', ''customer'': {''first_name'': ''asd'', ''last_name'': ''asd'', ''mail'': ''[email protected]'', ''phone_number'': 123123, ''id'': 1}, ''id'': 2, ''la'': 123123, ''ls'': 4512313, ''media_url'': ''h.com'', ''type'': ''image''}


Escribí una biblioteca para hacer esto: https://github.com/ltworf/typedload

Puede ir desde y hasta tuple-nombre y volver.

Es compatible con estructuras anidadas bastante complicadas, con listas, conjuntos, enumeraciones, uniones, valores predeterminados. Debe cubrir la mayoría de los casos comunes.


Esto es bastante complicado, ya que namedtuple() es una fábrica que devuelve un nuevo tipo derivado de tuple . Un enfoque sería tener su clase también UserDict.DictMixin de UserDict.DictMixin , pero la tuple.__getitem__ ya está definida y espera un entero que denote la posición del elemento, no el nombre de su atributo:

>>> f = foobar(''a'', 1) >>> f[0] ''a''

En su esencia, el timbre nombrado es un ajuste impar para JSON, ya que realmente es un tipo personalizado cuyos nombres de clave se fijan como parte de la definición de tipo , a diferencia de un diccionario donde los nombres de clave se almacenan dentro de la instancia. Esto le impide "disparar de forma redonda" a un grupo con nombre, por ejemplo, no puede decodificar un diccionario en un grupo con nombre sin otro elemento de información, como un marcador de tipo específico de aplicación en el dict {''a'': 1, ''#_type'': ''foobar''} , que es un poco hacky.

Esto no es ideal, pero si solo necesita codificar las bautizaciones nombradas en diccionarios, otro enfoque es extender o modificar su codificador JSON para estos tipos de casos especiales. Aquí hay un ejemplo de subclasificación de Python json.JSONEncoder . Esto aborda el problema de garantizar que las agrupaciones anidadas con nombre se conviertan correctamente en diccionarios:

from collections import namedtuple from json import JSONEncoder class MyEncoder(JSONEncoder): def _iterencode(self, obj, markers=None): if isinstance(obj, tuple) and hasattr(obj, ''_asdict''): gen = self._iterencode_dict(obj._asdict(), markers) else: gen = JSONEncoder._iterencode(self, obj, markers) for chunk in gen: yield chunk class foobar(namedtuple(''f'', ''foo, bar'')): pass enc = MyEncoder() for obj in (foobar(''a'', 1), (''a'', 1), {''outer'': foobar(''x'', ''y'')}): print enc.encode(obj) {"foo": "a", "bar": 1} ["a", 1] {"outer": {"foo": "x", "bar": "y"}}


Hay una solución más conveniente es usar el decorador (usa los campos de campo protegidos).

Python 2.7+:

import json from collections import namedtuple, OrderedDict def json_serializable(cls): def as_dict(self): yield OrderedDict( (name, value) for name, value in zip( self._fields, iter(super(cls, self).__iter__()))) cls.__iter__ = as_dict return cls #Usage: C = json_serializable(namedtuple(''C'', ''a b c'')) print json.dumps(C(''abc'', True, 3.14)) # or @json_serializable class D(namedtuple(''D'', ''a b c'')): pass print json.dumps(D(''abc'', True, 3.14))

Python 3.6.6+:

import json from typing import TupleName def json_serializable(cls): def as_dict(self): yield {name: value for name, value in zip( self._fields, iter(super(cls, self).__iter__()))} cls.__iter__ = as_dict return cls # Usage: @json_serializable class C(NamedTuple): a: str b: bool c: float print(json.dumps(C(''abc'', True, 3.14))


Parece que simplejson.JSONEncoder ser capaz de simplejson.JSONEncoder subclase de simplejson.JSONEncoder para hacer que esto funcione, pero con el último código de simplejson, ya no es el caso: tienes que modificar el código del proyecto. No veo ninguna razón por la que simplejson no deba admitir los timbres nombrados, por lo que he entregado el proyecto, agregué el soporte de timbres nombrados y actualmente estoy esperando que mi sucursal vuelva al proyecto principal . Si necesita las correcciones ahora, simplemente tire de mi tenedor.

EDITAR : Parece que las últimas versiones de simplejson ahora admiten esto de forma nativa con la opción namedtuple_as_object , que por defecto es True .


Si lo que buscas es serializar un solo namedtuple , usar el método _asdict() funcionará (con Python> = 2.7)

>>> from collections import namedtuple >>> import json >>> FB = namedtuple("FB", ("foo", "bar")) >>> fb = FB(123, 456) >>> json.dumps(fb._asdict()) ''{"foo": 123, "bar": 456}''