IT

이름이 tuple인 Python을 json으로 직렬화

itgroup 2023. 3. 19. 18:04
반응형

이름이 tuple인 Python을 json으로 직렬화

필드 이름을 유지한 상태에서 to json을 시리얼화하는 권장 방법은 무엇입니까?

의 시리얼화namedtupleto json을 지정하면 값만 시리얼화되고 필드 이름은 변환 중에 손실됩니다.json-izing 시 필드도 유지하여 다음 작업을 수행했으면 합니다.

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

위는 예상대로 json으로 시리얼화 되어 동작합니다.namedtuple다른 장소(속성 액세스 등)에서는, 반복하는 동안, 태플하지 않은 결과가 없는 경우(제 사용 예에서는 괜찮습니다).

필드 이름을 유지한 상태에서 json으로 변환하는 "올바른 방법"은 무엇입니까?

단 하나면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}'

이거 꽤 까다롭네요.namedtuple()에서 파생된 새로운 유형을 반환하는 공장입니다.tuple한 가지 접근법은 당신의 클래스도 상속받는 것입니다.UserDict.DictMixin,그렇지만tuple.__getitem__는 이미 정의되어 있으며 Atribute의 이름이 아닌 요소의 위치를 나타내는 정수를 필요로 합니다.

>>> 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"}}

당신은 예전엔 다른 분류를 할 수 있었나 보군요simplejson.JSONEncoder최신 simplejson 코드에서는 그렇지 않습니다.프로젝트 코드를 실제로 수정해야 합니다.simplejson이 namedtuples를 지원하지 않는 이유를 알 수 없기 때문에 프로젝트를 중단하고 namedtuples 지원을 추가하여 현재 본프로젝트에 브랜치가 복귀하기를 기다리고 있습니다.지금 당장 수정이 필요하면, 내 포크를 뽑아.

편집: 최신 버전의simplejson하고 있습니다.namedtuple_as_object 「」)입니다.True.

이 작업을 위해 라이브러리를 작성했습니다.https://github.com/ltworf/typedload

named-tuple에서 named-tuple로 이동할 수 있습니다.

리스트, 세트, Enum, 결합, 기본값을 사용하여 상당히 복잡한 중첩 구조를 지원합니다.대부분의 일반적인 경우를 대상으로 합니다.

edit: 라이브러리는 데이터 클래스 및 특성 클래스도 지원합니다.

네이티브 python json 라이브러리에서는 명명된 튜플을 올바르게 직렬화하는 것은 불가능합니다.항상 탭이 목록으로 표시되므로 기본 시리얼라이저를 덮어쓰고 이 동작을 변경할 수 없습니다.오브젝트가 중첩되어 있으면 더 나빠집니다.

orjson과 같은 보다 견고한 라이브러리를 사용하는 것이 좋습니다.

import orjson
from typing import NamedTuple

class Rectangle(NamedTuple):
    width: int
    height: int

def default(obj):
    if hasattr(obj, '_asdict'):
        return obj._asdict()

rectangle = Rectangle(width=10, height=20)
print(orjson.dumps(rectangle, default=default))

=>

{
    "width":10,
    "height":20
}

더 )._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))

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'}

jsonplus 라이브러리는 이름 지정의 시리얼라이저를 제공합니다.태플 인스턴스필요에 따라 호환성 모드를 사용하여 단순한 개체를 출력합니다.단, 디폴트는 디코딩에 도움이 되므로 우선합니다.

이것은 오래된 질문입니다.단,

하자면, 이 질문의 인 특징 중를 잘 해 보세요.의 프라이빗 기능 또는 내부 기능 중 하나를 사용하는 것을 신중하게 고려하십시오.NamedTuple왜냐하면 그들은 예전에도 그랬고 시간이 지나면 다시 변할 것이기 때문이다.

를 들어, '하다'가 '하다'라고 ,NamedTuple하지 않도록 할 수고를 피할 수.__dict__ 또는 제거됨_as_dict()변경 후 다음과 같은 작업을 수행합니다(이 답변은 현재용이므로 Python 3입니다).

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())

는 ★★★★★★★★★★★★★★★★★★★★★★를 사용해 보았다.default 가능한 에서 " "로dumps 위해서to_dict(), 않았다, 불리지 않았다.NamedTuple목록으로 변환할 수 있습니다.

그 문제에 대한 나의 견해는 이렇다.Named를 시리얼화합니다.터플, 접힌 이름 관리그 안에 있는 탭과 리스트

def recursive_to_dict(obj: Any) -> dict:
_dict = {}

if isinstance(obj, tuple):
    node = obj._asdict()
    for item in node:
        if isinstance(node[item], list): # Process as a list
            _dict[item] = [recursive_to_dict(x) for x in (node[item])]
        elif getattr(node[item], "_asdict", False): # Process as a NamedTuple
            _dict[item] = recursive_to_dict(node[item])
        else: # Process as a regular element
            _dict[item] = (node[item])
return _dict

simplejson.dump()json.dump그 일을 해냅니다.더 느릴 수도 있어요.

언급URL : https://stackoverflow.com/questions/5906831/serializing-a-python-namedtuple-to-json

반응형