Serializowanie Pythona nazwanego json
Jaki jest zalecany sposób serializacji a namedtuple
do jsona z zachowanymi nazwami pól?
namedtuple
do json powoduje serializację tylko wartości i utratę nazw pól podczas tłumaczenia. Chciałbym, aby pola również zostały zachowane, gdy json-ized i stąd zrobił następujące:
class foobar(namedtuple('f', 'foo, bar')):
__slots__ = ()
def __iter__(self):
yield self._asdict()
Powyższe serializuje się do json tak, jak oczekuję i zachowuje się jak namedtuple
w innych miejscach, których używam (dostęp do atrybutów itp.,) z wyjątkiem braku krotki jak wyniki podczas iteracja go (co jest dobre dla mojego przypadku użycia).
Jaki jest "prawidłowy sposób" konwersji do json z zachowanymi nazwami pól?
6 answers
Jest to dość trudne, ponieważ namedtuple()
jest fabryką, która zwraca nowy typ pochodzący z tuple
. Jedną z metod jest dziedziczenie klasy z UserDict.DictMixin
, ale {[5] } jest już zdefiniowana i oczekuje liczby całkowitej oznaczającej pozycję elementu, a nie nazwę jego atrybutu:
>>> f = foobar('a', 1)
>>> f[0]
'a'
W przeciwieństwie do słownika, w którym klucz jest zdefiniowany jako klucz, jest to typ Niestandardowy, którego nazwy są stałe w ramach definicji typu . nazwy są przechowywane wewnątrz instancji. Zapobiega to "round-potknięciu" nazwanego tuple, np. nie można dekodować słownika z powrotem do nazwanego tuple bez innych informacji, takich jak znacznik typu specyficznego dla aplikacji w dict {'a': 1, '#_type': 'foobar'}
, co jest nieco trudne.
Nie jest to idealne rozwiązanie, ale jeśli potrzebujesz tylko zakodować nazwapliki do słowników, innym podejściem jest rozszerzenie lub zmodyfikowanie kodera JSON na specjalne przypadki tego typu. Oto przykład podkategorii Python json.JSONEncoder
. To rozwiązuje problem zapewnienia, że zagnieżdżone namedtuples są poprawnie konwertowane do słowników: {]}
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"}}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-06 14:52:48
Jeśli jest to tylko jedna namedtuple
chcesz serializować, użycie jej metody _asdict()
będzie działać (z Pythonem >= 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}'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-09 14:31:57
Wygląda na to, że kiedyś byłeś w stanie podklasować simplejson.JSONEncoder
, aby to działało, ale z najnowszym kodem simplejson już tak nie jest: musisz faktycznie zmodyfikować kod projektu. Nie widzę powodu, dla którego simplejson nie miałby obsługiwać namedtuples, więc rozwidliłem projekt, dodałem namedtuple support, I jestem obecnie czekam, aż moja gałąź zostanie ściągnięta z powrotem do głównego projektu . Jeśli potrzebujesz poprawek teraz, po prostu wyciągnij z mojego widelca.
EDIT : wygląda jak najnowszy wersje simplejson
teraz natywnie wspierają to za pomocą opcji namedtuple_as_object
, która domyślnie wynosi True
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-06 20:17:53
Napisałem do tego bibliotekę: https://github.com/ltworf/typedload
Może przechodzić od I Do nazw-krotki i z powrotem.
Obsługuje dość skomplikowane zagnieżdżone struktury, z listami, zestawami, enumami, uniami, wartościami domyślnymi. Powinna ona obejmować najczęstsze przypadki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-07 22:20:22
Rekurencyjnie konwertuje namedTuple dane do 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'}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 13:08:52
Wygodniejszym rozwiązaniem jest użycie dekoratora(używa on chronionego pola _fields
).
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))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-07 14:19:27