Python json 인코더가 Python의 새 데이터 클래스를 지원하도록 합니다.
Python 3.7부터는 데이터 클래스라는 것이 있습니다.
from dataclasses import dataclass
@dataclass
class Foo:
x: str
그러나 다음은 실패합니다.
>>> import json
>>> foo = Foo(x="bar")
>>> json.dumps(foo)
TypeError: Object of type Foo is not JSON serializable
어떻게 만들 수 ?json.dumps()
의인스인의 합니다.Foo
json 객체로?
JSON 인코더에 객체 또는 소수점에 대한 지원을 추가할 수 있는 것처럼 사용자 지정 인코더 하위 클래스를 제공하여 데이터 클래스를 직렬화할 수도 있습니다.
import dataclasses, json
class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
json.dumps(foo, cls=EnhancedJSONEncoder)
당신은 그냥 사용할 수 없습니까?dataclasses.asdict()
데이터 클래스를 딕트로 변환하는 기능?다음과 같은 것:
>>> @dataclass
... class Foo:
... a: int
... b: int
...
>>> x = Foo(1,2)
>>> json.dumps(dataclasses.asdict(x))
'{"a": 1, "b": 2}'
JSONified 데이터 클래스 인스턴스를 가져오는 방법
이러한 목표를 달성하기 위한 몇 가지 옵션이 있습니다. 각 옵션을 선택하면 고객의 요구에 가장 적합한 접근 방식을 분석할 수 있습니다.
표준 라이브러리: dataclass.asdict
import dataclasses
import json
@dataclass.dataclass
class Foo:
x: str
foo = Foo(x='1')
json_foo = json.dumps(dataclasses.asdict(foo)) # '{"x": "1"}'
데이터 클래스 인스턴스로 다시 선택하는 것은 사소한 일이 아니므로 해당 답변을 방문하는 것이 좋습니다. https://stackoverflow.com/a/53498623/2067976
마시멜로 데이터 클래스
from dataclasses import field
from marshmallow_dataclass import dataclass
@dataclass
class Foo:
x: int = field(metadata={"required": True})
foo = Foo(x='1') # Foo(x='1')
json_foo = foo.Schema().dumps(foo) # '{"x": "1"}'
# Back to class instance.
Foo.Schema().loads(json_foo) # Foo(x=1)
보로스너의 로.marshmallow_dataclass
필드 자체에 대해 유효성 검사를 사용할 수 있습니다. 누군가가 해당 스키마를 사용하여 json의 개체를 역직렬화할 때 유효성 검사가 사용됩니다.
데이터 클래스 Json
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: int
foo = Foo(x='1')
json_foo = foo.to_json() # Foo(x='1')
# Back to class instance
Foo.from_json(json_foo) # Foo(x='1')
또한 마시멜로 데이터 클래스가 유형 변환을 수행했다는 사실도 알 수 있습니다. 반면 data classes-json(ver.: 0.5.1)은 이를 무시합니다.
쓰기 사용자 지정 인코더
승인된 Miracle2k 답변을 따르고 사용자 지정 json 인코더를 재사용합니다.
라이브러리를 사용해도 괜찮다면 dataclass-json을 사용할 수 있습니다.다음은 예입니다.
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: str
foo = Foo(x="some-string")
foo_json = foo.to_json()
또한 데이터 클래스에 다른 데이터 클래스로 입력된 필드가 있는 경우 포함된 데이터 클래스를 지원합니다. 관련된 모든 데이터 클래스가@dataclass_json
장식가
또다을구수있다니습할현을 할 수도 .asdict
그리고.json.dumps
클래스 내의 메서드입니다.이 경우에는 가져올 필요가 없습니다.json.dumps
프로젝트의 다른 부분으로:
from typing import List
from dataclasses import dataclass, asdict, field
from json import dumps
@dataclass
class TestDataClass:
"""
Data Class for TestDataClass
"""
id: int
name: str
tested: bool = False
test_list: List[str] = field(default_factory=list)
@property
def __dict__(self):
"""
get a python dictionary
"""
return asdict(self)
@property
def json(self):
"""
get the json formated string
"""
return dumps(self.__dict__)
test_object_1 = TestDataClass(id=1, name="Hi")
print(test_object_1.__dict__)
print(test_object_1.json)
출력:
{'id': 1, 'name': 'Hi', 'tested': False, 'test_list': []}
{"id": 1, "name": "Hi", "tested": false, "test_list": []}
메서드를 상속할 상위 클래스를 만들 수도 있습니다.
from typing import List
from dataclasses import dataclass, asdict, field
from json import dumps
@dataclass
class SuperTestDataClass:
@property
def __dict__(self):
"""
get a python dictionary
"""
return asdict(self)
@property
def json(self):
"""
get the json formated string
"""
return dumps(self.__dict__)
@dataclass
class TestDataClass(SuperTestDataClass):
"""
Data Class for TestDataClass
"""
id: int
name: str
tested: bool = False
test_list: List[str] = field(default_factory=list)
test_object_1 = TestDataClass(id=1, name="Hi")
print(test_object_1.__dict__)
print(test_object_1.json)
에 부모 를 만들 것을 to_json()
방법:
import json
from dataclasses import dataclass, asdict
@dataclass
class Dataclass:
def to_json(self) -> str:
return json.dumps(asdict(self))
@dataclass
class YourDataclass(Dataclass):
a: int
b: int
x = YourDataclass(a=1, b=2)
x.to_json() # '{"a": 1, "b": 2}'
이 기능은 모든 데이터 클래스에 추가할 다른 기능이 있는 경우 특히 유용합니다.
가장간인방법딩코한단방을 하는 가장 dataclass
그리고.SimpleNamespace
는 기본 을 객는기기제니다합공능에 제공하는 입니다.json.dumps()
수 합니다.__dict__
:
json.dumps(foo, default=lambda o: o.__dict__)
데이터 클래스 마법사는 사용자에게 유용한 최신 옵션입니다.날짜 및 시간과 같은 복잡한 유형을 지원합니다. 대부분의 일반 데이터는typing
모듈 및 중첩된 데이터 클래스 구조입니다.
PEP 585 및 604에 도입된 "새로운 스타일" 주석은 다음을 통해 Python 3.7로 포팅할 수 있습니다.__future__
아래와 같이 수입합니다.
from __future__ import annotations # This can be removed in Python 3.10
from dataclasses import dataclass, field
from dataclass_wizard import JSONWizard
@dataclass
class MyClass(JSONWizard):
my_str: str | None
is_active_tuple: tuple[bool, ...]
list_of_int: list[int] = field(default_factory=list)
string = """
{
"my_str": 20,
"ListOfInt": ["1", "2", 3],
"isActiveTuple": ["true", false, 1]
}
"""
instance = MyClass.from_json(string)
print(repr(instance))
# MyClass(my_str='20', is_active_tuple=(True, False, True), list_of_int=[1, 2, 3])
print(instance.to_json())
# '{"myStr": "20", "isActiveTuple": [true, false, true], "listOfInt": [1, 2, 3]}'
# True
assert instance == MyClass.from_json(instance.to_json())
데이터 클래스 마법사를 설치할 수 있습니다.pip
:
$ pip install dataclass-wizard
약간의 배경 정보:
직렬화의 경우 약간 수정된 (조금 더 효율적인) 구현을 사용합니다. JSON을 데이터 클래스 인스턴스로 직렬화 해제할 때 JSON은 데이터 클래스 필드를 통해 처음 반복되고 주석이 달린 각 유형에 대한 파서를 생성하므로 직렬화 해제 프로세스가 여러 번 실행될 때 더 효율적입니다.
고지 사항:저는 이 라이브러리의 작성자(및 유지관리자)입니다.
익살스러운
pydantic 모델을 사용하면 데이터 클래스와 유사한 환경을 경험할 수 있고 딕트 및 Json 변환을 완벽하게 지원할 수 있습니다.
Python 3.9 이상:
from typing import Optional
from pydantic import BaseModel, parse_obj_as, parse_raw_as
class Foo(BaseModel):
count: int
size: Optional[float] = None
f1 = Foo(count=10)
# Parse to dict
print(f1.dict())
# OUT: {'count': 10, 'size': None}
# Load from dict
f2 = Foo.parse_obj({"count": 20})
# Parse to json
print(f2.json())
# OUT: {"count": 20, "size": null}
추가 옵션:
# Load from json string
f3 = Foo.parse_raw('{"count": 30}')
# Load from json file
f4 = Foo.parse_file("path/to/data.json")
# Load from list of dicts
f_list1 = parse_obj_as(list[Foo], [{"count": 110}, {"count": 120}])
print(f_list1)
# OUT: [Foo(count=110, size=None), Foo(count=120, size=None)]
# Load from list in json string
f_list2 = parse_raw_as(list[Foo], '[{"count": 130}, {"count": 140}]')
print(f_list2)
# OUT: [Foo(count=130, size=None), Foo(count=140, size=None)]
복잡한 계층형 데이터 구조
class Bar(BaseModel):
apple = "x"
banana = "y"
class Spam(BaseModel):
foo: Foo
bars: list[Bar]
m = Spam(foo={"count": 4}, bars=[{"apple": "x1"}, {"apple": "x2"}])
print(m)
# OUT: foo=Foo(count=4, size=None) bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y')]
print(m.dict())
# OUT:
# {
# 'foo': {'count': 4, 'size': None},
# 'bars': [
# {'apple': 'x1', 'banana': 'y'},
# {'apple': 'x2', 'banana': 'y'},
# ],
# }
Pydantic은 다양한 표준 유형을 지원합니다(예:datetime
) 및 일반적으로 사용되는 특수 유형(예:EmailStr
그리고.HttpUrl
):
from datetime import datetime
from pydantic import HttpUrl
class User(BaseModel):
name = "John Doe"
signup_ts: datetime = None
url: HttpUrl = None
u1 = User(signup_ts="2017-07-14 00:00:00")
print(u1)
# OUT: signup_ts=datetime.datetime(2017, 7, 14, 0, 0) url=None name='John Doe'
u2 = User(url="http://example.com")
print(u2)
# OUT: signup_ts=None url=HttpUrl('http://example.com', ) name='John Doe'
u3 = User(url="ht://example.com")
# OUT:
# ValidationError: 1 validation error for User
# url
# URL scheme not permitted (type=value_error.url.scheme; allowed_schemes={'http', 'https'})
정말로 사용해야 하는 경우json.dumps
사용자 지정 인코더 작성:
import json
class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, BaseModel):
return o.dict()
return super().default(o)
foo = Foo(count=20)
json.dumps([{"foo": foo}], cls=EnhancedJSONEncoder)
# OUT: '[{"foo": {"count": 20, "size": null}}]'
json 형성 방법을 제공하는 데이터 클래스
import json
from dataclasses import dataclass
@dataclass
class Foo:
x: str
def to_json(self):
return json.dumps(self.__dict__)
Foo("bar").to_json()
>>> '{"x":"bar"}'
사전 압축 풀기를 사용하여 훨씬 더 간단한 답을 Reddit에서 찾을 수 있습니다.
>>> from dataclasses import dataclass
>>> @dataclass
... class MyData:
... prop1: int
... prop2: str
... prop3: int
...
>>> d = {'prop1': 5, 'prop2': 'hi', 'prop3': 100}
>>> my_data = MyData(**d)
>>> my_data
MyData(prop1=5, prop2='hi', prop3=100)
자, 여기 제가 비슷한 상황에 처했을 때 한 일이 있습니다.
중첩된 데이터 클래스를 사전으로 변환하는 사용자 정의 사전 팩토리를 만듭니다.
def myfactory(data): dict 반환(x[1]이 None이 아닌 경우 x는 데이터의 x에 해당)
foo가 @data 클래스인 경우 사전 팩토리에서 "myfactory()" 메서드를 사용하도록 제공하기만 하면 됩니다.
fooDict = asdict(foo, dict_factory=myfactory)
fooDict를 json으로 변환
fooJson = json.dump(fooDict)
이것은 효과가 있을 것입니다!!
언급URL : https://stackoverflow.com/questions/51286748/make-the-python-json-encoder-support-pythons-new-dataclasses
'programing' 카테고리의 다른 글
C++에 모든 것이 포함되어 있기 때문에 C를 배울 필요가 없다는 것이 사실입니까? (0) | 2023.06.13 |
---|---|
뷰 상태 디코딩 방법 (0) | 2023.06.13 |
왜 VB가.문자열만 반환하는 Net 함수는 실제로 한 글자만 반환합니까? (0) | 2023.06.13 |
mysqdump는 MariaDB 5.5의 데이터베이스에 테이블을 덤프하지 않습니다. (0) | 2023.06.08 |
모카 유닛 테스트에 대한 사용자 정의 오류 메시지와 함께 차이 기대치를 제공하는 방법은 무엇입니까? (0) | 2023.06.08 |