Python namedtuple을 json으로 직렬화
namedtuple
유지 된 필드 이름으로 json 에 직렬화하는 권장 방법은 무엇입니까 ?
a namedtuple
를 json으로 직렬화하면 값이 직렬화되고 필드 이름이 변환에서 손실됩니다. json-ized 때 필드도 유지되기를 원하므로 다음을 수행했습니다.
class foobar(namedtuple('f', 'foo, bar')):
__slots__ = ()
def __iter__(self):
yield self._asdict()
위의 내용은 내가 예상 한대로 json으로 직렬화하고 namedtuple
내가 사용하는 다른 장소 (속성 액세스 등)에서 와 같이 동작 합니다. 단, 반복하는 동안 튜플과 같은 결과가 아닌 경우 (내 사용 사례에 적합)를 제외하고는 작동합니다.
필드 이름이 유지 된 상태에서 json으로 변환하는 "올바른 방법"은 무엇입니까?
namedtuple()
에서 파생 된 새로운 유형을 반환하는 팩토리 이기 때문에 이것은 꽤 까다 롭습니다 tuple
. 한 가지 방법은 클래스도에서 상속하도록하는 UserDict.DictMixin
것이지만 tuple.__getitem__
이미 정의되어 있으며 속성 이름이 아닌 요소의 위치를 나타내는 정수를 예상합니다.
>>> f = foobar('a', 1)
>>> f[0]
'a'
기본적으로 namedtuple은 키 이름이 인스턴스 내부에 저장되는 사전과 달리 키 이름이 유형 정의의 일부로 고정 되는 사용자 지정 빌드 유형 이므로 JSON에 이상하게 맞습니다 . 이렇게하면 명명 된 튜플을 "왕복"하는 것을 방지 할 수 있습니다. 예를 들어 dict의 앱 특정 유형 마커와 같은 다른 정보 없이는 사전을 명명 된 튜플로 다시 디코딩 할 수 없습니다 {'a': 1, '#_type': 'foobar'}
.
이것은 이상적이지는 않지만 명명 된 튜플을 사전 으로 인코딩하기 만하면되는 경우 다른 접근 방식은 JSON 인코더를 이러한 유형의 특수 사례로 확장하거나 수정하는 것입니다. 다음은 Python을 서브 클래 싱하는 예입니다 json.JSONEncoder
. 이렇게하면 중첩 된 명명 된 튜플이 사전으로 제대로 변환되는지 확인하는 문제가 해결됩니다.
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"}}
namedtuple
직렬화하려는 경우에만 해당 _asdict()
메서드를 사용 하면 작동합니다 (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}'
simplejson.JSONEncoder
이 작업을 수행하기 위해 서브 클래스를 사용할 수 있었던 것처럼 보이지만 최신 simplejson 코드에서는 더 이상 그렇지 않습니다. 실제로 프로젝트 코드를 수정해야합니다. simplejson이 namedtuple을 지원하지 않아야 할 이유가 없으므로 프로젝트를 분기하고 namedtuple 지원을 추가했으며 현재 브랜치가 메인 프로젝트로 돌아 오기를 기다리고 있습니다 . 지금 수정이 필요하면 내 포크에서 꺼내십시오.
편집 : 최신 버전처럼 보인다는 simplejson
이제 기본적으로 이것을 지원 namedtuple_as_object
되는 디폴트 옵션 True
.
이 작업을 위해 라이브러리를 작성했습니다 : https://github.com/ltworf/typedload
명명 된 튜플 사이를 오가고 돌아갈 수 있습니다.
목록, 집합, 열거 형, 공용체, 기본값이있는 매우 복잡한 중첩 구조를 지원합니다. 대부분의 일반적인 경우를 다루어야합니다.
편집 : 라이브러리는 데이터 클래스 및 속성 클래스도 지원합니다.
namedTuple 데이터를 재귀 적으로 json으로 변환합니다.
print(m1)
## Message(id=2, agent=Agent(id=1, first_name='asd', last_name='asd', mail='2@mai.com'), customer=Customer(id=1, first_name='asd', last_name='asd', mail='2@mai.com', 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': '2@mai.com',
'id': 1},
'content': 'text',
'customer': {'first_name': 'asd',
'last_name': 'asd',
'mail': '2@mai.com',
'phone_number': 123123,
'id': 1},
'id': 2,
'la': 123123,
'ls': 4512313,
'media_url': 'h.com',
'type': 'image'}
더 편리한 해결책은 데코레이터를 사용하는 것입니다 (보호 된 필드를 사용합니다 _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))
jsonplus의 라이브러리는 NamedTuple 인스턴스들에 대한 serializer를 제공합니다. 필요한 경우 호환 모드를 사용하여 간단한 개체를 출력하지만 다시 디코딩하는 데 도움이되는 기본값을 선호합니다.
이것은 오래된 질문입니다. 하나:
같은 질문을 가진 모든 사람들을위한 제안입니다.의 사적 또는 내부 기능 중 하나를 사용하는 것에 대해 신중하게 생각 NamedTuple
하십시오. 이전에 가지고 있었고 시간이 지남에 따라 다시 변경 될 것입니다.
For example, if your NamedTuple
is a flat value object and you're only interested in serializing it and not in cases where it is nested into another object, you could avoid the troubles that would come up with __dict__
being removed or _as_dict()
changing and just do something like (and yes this is Python 3 because this answer is for the present):
from typing import NamedTuple
class ApiListRequest(NamedTuple):
group: str="default"
filter: str="*"
def to_dict(self):
return {
'group': self.group,
'filter': self.filter,
}
def to_json(self):
return json.dumps(self.to_dict())
I tried to use the default
callable kwarg to dumps
in order to do the to_dict()
call if available, but that didn't get called as the NamedTuple
is convertible to a list.
참고URL : https://stackoverflow.com/questions/5906831/serializing-a-python-namedtuple-to-json
'Program Tip' 카테고리의 다른 글
OpenSSL을 사용하여 .c 파일을 컴파일하는 방법은 무엇입니까? (0) | 2020.11.14 |
---|---|
Python에서 클래스의 멤버 변수에 액세스합니까? (0) | 2020.11.14 |
전체 디렉토리에 대한 패치를 작성하여 업데이트하는 방법은 무엇입니까? (0) | 2020.11.14 |
애니메이션이있는 함수가 다른 함수를 실행할 때까지 완료 될 때까지 기다립니다. (0) | 2020.11.14 |
내 gradle 빌드에 로컬 .aar 파일 추가 (0) | 2020.11.14 |