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() 「」, 「」가 없으면,skipkeys로 True그것은 을 올릴 것이다.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
'programing' 카테고리의 다른 글
| 워드프레스의 하위 도메인이 계속 주 도메인으로 리디렉션됨 (0) | 2023.03.28 |
|---|---|
| 값에 따른 json의 python 정렬 목록 (0) | 2023.03.28 |
| JSON 문자열을 jq(또는 다른 대체)로 해석하는 방법 (0) | 2023.03.28 |
| Angular가 있는 루프 내부의 라벨을 사용하는 방법JS (0) | 2023.03.28 |
| Formik과 함께 Material-UI의 자동 완성 구성요소 사용 (0) | 2023.03.28 |