Python을 사용하여 객체 Enceode/Decode를 JSON에 연결
개시하다
파이톤에는 json이라는 모듈이 있는데, 일반적으로 사용하면 Enceode/Decode는 dict 형식으로 진행된다.
이 상태에서도 충분히 활용할 수 있지만 자바스크립트 오브젝트 노트인데 대상이 안 되는 건 좀 불편하지 않나요?따라서 개체 JSON 문자열의 변환이 요약됩니다.
기본 사전 형식의 Enceode/Decode에 관해서는 여기를 참조하십시오. 하십시오.
TL;DR
어쨌든 간단한 대상은 다음과 같은 요령에 따라 처리할 수 있다.
import json
from types import SimpleNamespace
# オブジェクト定義
# コンストラクタのある場合
class Foo():
def __init__(self, hoge1: str, hogeNum: int, hoge_list: list) -> None:
self.hoge1 = hoge1
self.hogeNum = hogeNum
self.hoge_list = hoge_list
f = Foo("hoge1", 192, [1, 2, 3])
# コンストラクタの無い場合
class Hoge():
pass
h = Hoge()
h.hoge = "hogehoge"
h.hoga = "hogahoga"
h.num = 123
h.num_list = [1, 2, 3]
# Encode時
# オブジェクトから __dict__ を通じてAttributeの辞書を取得し、JSONに
json_str = json.dumps(f.__dict__)
print(json_str)
# >> {"hoge1": "hoge1", "hogeNum": 192, "hoge_list": [1, 2, 3]}
h_str = json.dumps(h.__dict__)
print(h_str)
# >> {"hoge": "hogehoge", "hoga": "hogahoga", "num": 123, "num_list": [1, 2, 3]}
# Decode時
# object_hookにコンストラクタをいれる(辞書で受けた引数を展開する)
# コンストラクタが未定義の場合:
# types モジュールのSimpleNamespaceを使う
f = json.loads(json_str, object_hook=lambda x: Foo(**x))
print(f.hoge1) # >> hoge1
h = json.loads(h_str, object_hook=lambda x: SimpleNamespace(**x))
print(h.num_list) # >> [1, 2, 3]
도서관 없어요?
'json tricks'라는 모듈이 있는데 자신이 노력하지 않아도 간단하게 대상을 JSON화할 수 있다.
그러나 이는 이 모듈을 통해 Enceode와 Decode 쌍방을 진행하는 것을 전제로 하기 때문에 이미 정해진 JSON 대상을 처리할 때 스스로 써야 한다.
다른 것은'ijson'이라는 도서관도 있다.수십 MB가 넘는 데이터를 모두 메모리에 읽지 않고도 사용할 수 있는 대규모 데이터 분석 도구지만, 목적 대상과는 읽기와 쓰기가 조금 다르다.
결론: 자신에게 맞는 것은 스스로 할 수밖에 없다.
기본 이념
json 모듈의 loads(load)에서 obj 매개 변수는 Any이지만 일반적으로 대상을 넣으면 Typereror가 나타납니다.
class Hoge():
pass
h = Hoge()
h.hoge = "hogehoge"
h.hoga = "hogahoga"
h.num = 123
h.num_list = [1, 2, 3]
h_str = json.dumps(h)
# TypeError: Object of type Hoge is not JSON serializable
개체가 이미 정의된 Enceoder에서 참조하는 변환 테이블에 변환 개체로 들어가지 않았기 때문입니다.Python→JSON의 변환표 (공식)
따라서
__dict__
를 사용하여 대상이 정의한 속성을 사전 형식으로 가져오고 전달한다.__dict__
상세 정보여기(공식)h_str = json.dumps(h.__dict__)
print(h_str)
# {"hoge": "hogehoge", "hoga": "hogahoga", "num": 123, "num_list": [1, 2, 3]}
직접 두드릴 수 없으면 dict 형식으로 변환하는 함수를 만드십시오.클래스에서 개인 변수
__dict__
를 정의하면 내용이 특수해지기 때문에 이런 상황에서도 함수를 만들어야 한다.class Foo():
def __init__(self, hoge:str):
self.hoge = hoge
self.__hoge = "private value"
f = Foo("foo")
print(f.__dict__)
# >> {'hoge': 'foo', '_Foo__hoge': 'private value'}
# 属性名が一致していないので再現が難しい
기본 설계
Decode에서 매개변수
__dict__
를 사용합니다.함수를 여기에 전달하면 Enceod에서 Object 요소가 감지될 때 함수가 호출됩니다.
매개 변수로서 내용이 dict 형식으로 전달되기 때문에 이를 구조기에 전개한다.
매개 변수에 대한 사전 전개여기.
정의된 구조기가 없는 클래스에서도 types 모듈에서 가져오면
object_hook
대상으로 간단하게 복원할 수 있습니다.그러나 완성된 대상은 원래의 종류와 다르기 때문에 방법과 속성을 호출할 수 없다.
from types import SimpleNamespace
h = json.loads(h_str, object_hook=lambda x: SimpleNamespace(**x))
print(h.num_list) # >> [1, 2, 3]
복잡한 속성을 가진 클래스 처리
위의 예에서 문자, 수치, 배열 등 JSON에서도 이미 정해진 요소로 구성된 대상만 처리한다.
그러나 실제 대상에는 다양한 요소가 포함될 수 있다.
이럴 때는 상술한 방법만으로는 해결할 수 없기 때문에 스스로 좀 더 실시해야 한다.
Enceode 시
json 모듈 내의 JSONI Coder를 계승한 단독 반을 생성하고dupp/dumps를 칠 때cls 매개 변수를 건네줍니다.
클래스에서defaut 방법을 다시 쓰고 대상 형식에 따라 복구 가능한 dict 형식으로 변환합니다.
구체적으로 말하면 키에 설정된 문자열이 속성 (attrabute) 의 이름으로 덮어쓰지 않는다는 것을 복구할 수 있다.
Decode에서 읽은 dict의 키는 원래 대상으로 되돌아갑니다. 그러나 속성 이름이 덮어쓰이면 복원에 실패합니다.
다만 언어는 이해하기 어렵지만 다음과 같은 느낌이 든다.
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, uuid.UUID):
# 属性名と被らないようなKeyを設定して辞書形式で返す。
return {"__uuid__": str(obj)}
elif isinstance(obj, object) and hasattr(obj, '__dict__'):
# 一般的なクラスオブジェクトは__dict__で返す。
return obj.__dict__
# 数値や文字列など元のJSONに含まれるものは元のEncoderを使う。
return json.JSONEncoder.default(self, obj)
json.dumps(h, cls=MyEncoder)
Decode 시
Enceode 때와 마찬가지로 JSOND ecoder를 계승하는 독립반을 만들 필요가 없고
SimpleNamespace
에 전달되는 의식을 정의하면 된다.Encode 에서 설정한 키 값에 따라 읽기 값을 복원하는 처리를 추가합니다.
def decode(d: dict):
if "__uuid__" in d:
return uuid.UUID(d["__uuid__"])
return SimpleNamespace(**d)
# return d にすると最終的に特定のkeyに対応するオブジェクトが変換した状態のdictが返される。
json.loads(h_json, object_hook=decode)
Example
이상의 총결은 아래와 같다.
import json
import uuid
class Hoge():
pass
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, uuid.UUID):
return {"__uuid__": str(obj)}
elif isinstance(obj, object) and hasattr(obj, '__dict__'):
return obj.__dict__
return json.JSONEncoder.default(self, obj)
def decode(d: dict):
if "__uuid__" in d:
return uuid.UUID(d["__uuid__"])
return SimpleNamespace(**d)
h = Hoge()
h.id = uuid.uuid1()
h.hoge_str = "hoge"
c = Hoge()
c.c_str = "child"
h.child = c
# cls引数に作成したクラスを渡してやり、obj引数にはオブジェクトをそのまま渡す。
h_json = json.dumps(h, cls=MyEncoder)
print(h_json)
# >> {"id": {"__uuid__": "生成されたuuidの値"}, "hoge_str": "hoge", "child": {"c_str": "child"}}
h = json.loads(h_json, object_hook=decode)
print(h.id) # >> (生成されたuuidの値)
print(h.child.c_str) # >> child
Reference
이 문제에 관하여(Python을 사용하여 객체 Enceode/Decode를 JSON에 연결), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/ku_mal/articles/b136b9394031a3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)