programing

Python의 json.dumps가 직렬화 불가능한 필드를 무시하도록 하는 방법

iphone6s 2023. 3. 28. 21:19
반응형

Python의 json.dumps가 직렬화 불가능한 필드를 무시하도록 하는 방법

Construct2.9 라이브러리를 사용하여 바이너리 데이터를 해석하는 출력을 시리얼화하려고 합니다.JSON에 결과를 연재하고 싶습니다.

packetConstruct 클래스의 인스턴스입니다.Container.

숨겨져 있는 게 있대요_io타입의BytesIO- 출력 참조dict(packet)이하에 나타냅니다.

{
'packet_length': 76, 'uart_sent_time': 1, 'frame_number': 42958, 
'subframe_number': 0, 'checksum': 33157, '_io': <_io.BytesIO object at 0x7f81c3153728>, 
'platform':661058, 'sync': 506660481457717506, 'frame_margin': 20642,
'num_tlvs': 1, 'track_process_time': 593, 'chirp_margin': 78,
'timestamp': 2586231182, 'version': 16908293
}

자, 전화하고 있습니다.json.dumps(packet)분명히 TypeError로 이어집니다.

...

File "/usr/lib/python3.5/json/__init__.py", line 237, in dumps
    **kw).encode(obj)
File "/usr/lib/python3.5/json/encoder.py", line 198, in encode
    chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode
    return _iterencode(o, 0)
File "/usr/lib/python3.5/json/encoder.py", line 179, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <_io.BytesIO object at 0x7f81c3153728> is not JSON serializable

하지만 내가 혼란스러운 건 도망가는 게json.dumps(packet, skipkeys=True)같은 에러가 발생합니다만, 이 에러는 생략할 수 있습니다._io현장입니다. 뭐가 문제죠?왜?skipkeys내가 이 일을 건너뛰는 것을 허락하지 않는다._io필드?

오버라이드하여 동작하는 코드를 취득했습니다.JSONEncoder돌아오다None의 분야에 대해서BytesIOtype, 단, 시리얼화된 문자열에 로드가 포함되어 있는 것을 의미합니다."_io": null전 전혀 갖고 싶지 않은...

선두가 있는 키_언더스코어는 실제로 '숨김'이 아니라 JSON에 대한 문자열일 뿐입니다.구성Containerclass는 순서를 매긴 사전일 뿐입니다._io키는 그 클래스에 특별한 것이 아닙니다.

두 가지 옵션이 있습니다.

  • 을 실행하다default대체값을 반환하는 후크입니다.
  • 직렬화하기 전에 사용할 수 없는 키와 값의 쌍을 필터링하십시오.

세 번째일 수도 있지만 Construct 프로젝트 페이지를 대충 스캔해도 사용할 수 있는지 알 수 없습니다.어댑터를 사용하여 출력 JSON 또는 적어도 JSON 호환 사전을 사용할 수 있습니다.

디폴트 훅으로 인해_io키는 출력에 추가되지 않지만 최소한 오류는 방지할 수 있습니다.

json.dumps(packet, default=lambda o: '<not serializable>')

필터링은 재귀적으로 실행할 수 있습니다.디케이터는 이러한 코드를 깨끗하게 유지하는 데 도움이 됩니다.

from functools import singledispatch

_cant_serialize = object()

@singledispatch
def json_serializable(object, skip_underscore=False):
    """Filter a Python object to only include serializable object types

    In dictionaries, keys are converted to strings; if skip_underscore is true
    then keys starting with an underscore ("_") are skipped.

    """
    # default handler, called for anything without a specific
    # type registration.
    return _cant_serialize

@json_serializable.register(dict)
def _handle_dict(d, skip_underscore=False):
    converted = ((str(k), json_serializable(v, skip_underscore))
                 for k, v in d.items())
    if skip_underscore:
        converted = ((k, v) for k, v in converted if k[:1] != '_')
    return {k: v for k, v in converted if v is not _cant_serialize}

@json_serializable.register(list)
@json_serializable.register(tuple)
def _handle_sequence(seq, skip_underscore=False):
    converted = (json_serializable(v, skip_underscore) for v in seq)
    return [v for v in converted if v is not _cant_serialize]

@json_serializable.register(int)
@json_serializable.register(float)
@json_serializable.register(str)
@json_serializable.register(bool)  # redudant, supported as int subclass
@json_serializable.register(type(None))
def _handle_default_scalar_types(value, skip_underscore=False):
    return value

위의 구현이 있습니다.skip_underscore인수가 있는 키도 명시적으로 건너뜁니다._선두에 문자를 입력합니다.이렇게 하면 Construct 라이브러리에서 사용 중인 추가 '숨김' 특성을 모두 건너뛸 수 있습니다.

부터Container는 입니다.dict서브클래스, 위의 코드는 다음과 같은 인스턴스를 자동으로 처리합니다.packet.

직렬화할 수 없는 필드를 무시하려면 이전 모든 답변에서 올바르게 지적한 대로 무거운 추가 논리가 필요합니다.

필드를 제외할 필요가 없는 경우 기본값을 대신 생성할 수 있습니다.

def safe_serialize(obj):
  default = lambda o: f"<<non-serializable: {type(o).__qualname__}>>"
  return json.dumps(obj, default=default)

obj = {"a": 1, "b": bytes()} # bytes is non-serializable by default
print(safe_serialize(obj))

그 결과 다음과 같은 결과가 나타납니다.

{"a": 1, "b": "<<non-serializable: bytes>>"}

이 코드는 유형 이름을 인쇄하므로 나중에 사용자 지정 직렬화기를 구현할 때 유용합니다.

skipkeys 는, 생각하시는 대로 동작하지 않습니다.키 값이 아닌 기본 타입의 키를 건너뛰도록 지시합니다.즉, 키 값이 있는 경우입니다.dict {object(): "foobar"}할 수 .object() 「」, 「」가 없으면,skipkeysTrue그것은 을 올릴 것이다.TypeError.

여기서 오버로드(및 그 언더배)와 미리 보기 필터링을 실행할 수 있지만, 결과적으로 거의 다시 작성하게 됩니다.json컴파일된 부품의 이점을 얻을 수 없기 때문에 프로세스 속도가 느려집니다.반복 필터링을 통해 데이터를 사전 처리하고 최종 JSON에서 원하지 않는 키/유형을 건너뛸 것을 권장합니다. '하다'는json모듈이 추가 지시 없이 처리할 수 있어야 합니다.예를 들어 다음과 같습니다.

import collections

class SkipFilter(object):

    def __init__(self, types=None, keys=None, allow_empty=False):
        self.types = tuple(types or [])
        self.keys = set(keys or [])
        self.allow_empty = allow_empty  # if True include empty filtered structures

    def filter(self, data):
        if isinstance(data, collections.Mapping):
            result = {}  # dict-like, use dict as a base
            for k, v in data.items():
                if k in self.keys or isinstance(v, self.types):  # skip key/type
                    continue
                try:
                    result[k] = self.filter(v)
                except ValueError:
                    pass
            if result or self.allow_empty:
                return result
        elif isinstance(data, collections.Sequence):
            result = []  # a sequence, use list as a base
            for v in data:
                if isinstance(v, self.types):  # skip type
                    continue
                try:
                    result.append(self.filter(v))
                except ValueError:
                    pass
            if result or self.allow_empty:
                return result
        else:  # we don't know how to traverse this structure...
            return data  # return it as-is, hope for the best...
        raise ValueError

그런 다음 필터를 만듭니다.

import io

preprocessor = SkipFilter([io.BytesIO], ["_io"])  # double-whammy skip of io.BytesIO

에는 그냥 , 이 라면,_iokey에는 다른 바람직하지 않은 데이터가 저장되어 있기 때문에 최종 결과에는 포함되지 않습니다., 「」, 「」에.JSONEncoder:

import json

json_data = json.dumps(preprocessor.filter(packet))  # no _io keys or io.BytesIO data...

그 JSON에서 데이터나 되어 있는 , 이 매핑을 JSON으로 을 일으킬 수 .dict를 「」로 합니다.list다만, 일반적인 사용의 경우는, 이것만으로 충분합니다.

언급URL : https://stackoverflow.com/questions/51674222/how-to-make-json-dumps-in-python-ignore-a-non-serializable-field

반응형