python에서 json 문자열을 개체로 역직렬화합니다.
다음과 같은 문자열이 있습니다.
{"action":"print","method":"onData","data":"Madan Mohan"}
클래스 객체로 역직렬화하려고 합니다.
class payload
string action
string method
string data
python 2.6과 2.7을 사용하고 있습니다.
>>> j = '{"action": "print", "method": "onData", "data": "Madan Mohan"}'
>>> import json
>>>
>>> class Payload(object):
... def __init__(self, j):
... self.__dict__ = json.loads(j)
...
>>> p = Payload(j)
>>>
>>> p.action
'print'
>>> p.method
'onData'
>>> p.data
'Madan Mohan'
Sami의 답변을 자세히 설명하자면:
문서에서:
class Payload(object):
def __init__(self, action, method, data):
self.action = action
self.method = method
self.data = data
import json
def as_payload(dct):
return Payload(dct['action'], dct['method'], dct['data'])
payload = json.loads(message, object_hook = as_payload)
에 대한 나의 이의
.__dict__
해결 방법은 작업을 수행하고 간결하지만 페이로드 클래스는 완전히 일반화되어 해당 필드를 문서화하지 않습니다.
예를 들어 Payload 메시지의 형식이 예기치 않은 경우 Payload 작성 시 키를 찾을 수 없음 오류가 발생하는 대신 payload가 사용될 때까지 오류가 생성되지 않습니다.
Python 3.6의 타입 힌트를 채용하고 있는 경우는, 다음과 같이 실행할 수 있습니다.
def from_json(data, cls):
annotations: dict = cls.__annotations__ if hasattr(cls, '__annotations__') else None
if issubclass(cls, List):
list_type = cls.__args__[0]
instance: list = list()
for value in data:
instance.append(from_json(value, list_type))
return instance
elif issubclass(cls, Dict):
key_type = cls.__args__[0]
val_type = cls.__args__[1]
instance: dict = dict()
for key, value in data.items():
instance.update(from_json(key, key_type), from_json(value, val_type))
return instance
else:
instance : cls = cls()
for name, value in data.items():
field_type = annotations.get(name)
if inspect.isclass(field_type) and isinstance(value, (dict, tuple, list, set, frozenset)):
setattr(instance, name, from_json(value, field_type))
else:
setattr(instance, name, value)
return instance
그런 다음 다음과 같이 입력된 개체를 인스턴스화할 수 있습니다.
class Bar:
value : int
class Foo:
x : int
bar : List[Bar]
obj : Foo = from_json(json.loads('{"x": 123, "bar":[{"value": 3}, {"value": 2}, {"value": 1}]}'), Foo)
print(obj.x)
print(obj.bar[2].value)
그러나 이 구문에는 Python 3.6이 필요하며, 예를 들어 입력 지원 등 모든 대소문자를 포함하는 것은 아닙니다.임의의... 하지만 적어도 추가 init/tojson 메서드로 역직렬화해야 하는 클래스를 오염시키지는 않습니다.
파이썬의 최신 버전에서는 마시멜로 데이터 클래스를 사용할 수 있습니다.
from marshmallow_dataclass import dataclass
@dataclass
class Payload
action:str
method:str
data:str
Payload.Schema().load({"action":"print","method":"onData","data":"Madan Mohan"})
나는 이 '도전'을 해결하느라 머리가 다 빠졌다고 생각했다.다음과 같은 문제에 직면했습니다.
- 중첩된 개체, 목록 등을 역직렬화하는 방법
- 지정된 필드를 가진 생성자가 좋습니다.
- 동적 필드를 좋아하지 않습니다.
- 나는 진부한 해결책을 좋아하지 않는다.
나는 라는 도서관을 찾았다.jsonpickle
정말 유용하다는 것이 증명되었습니다.
설치:
pip install jsonpickle
다음은 파일에 중첩된 개체를 쓰는 코드 예제입니다.
import jsonpickle
class SubObject:
def __init__(self, sub_name, sub_age):
self.sub_name = sub_name
self.sub_age = sub_age
class TestClass:
def __init__(self, name, age, sub_object):
self.name = name
self.age = age
self.sub_object = sub_object
john_junior = SubObject("John jr.", 2)
john = TestClass("John", 21, john_junior)
file_name = 'JohnWithSon' + '.json'
john_string = jsonpickle.encode(john)
with open(file_name, 'w') as fp:
fp.write(john_string)
john_from_file = open(file_name).read()
test_class_2 = jsonpickle.decode(john_from_file)
print(test_class_2.name)
print(test_class_2.age)
print(test_class_2.sub_object.sub_name)
출력:
John
21
John jr.
웹사이트: http://jsonpickle.github.io/
그것이 당신의 시간을 절약해 주길 바랍니다.
코드 행을 저장하고 가장 유연한 솔루션을 남겨두고 싶은 경우 동적 객체로 json 문자열을 역직렬화할 수 있습니다.
p = lambda:None
p.__dict__ = json.loads('{"action": "print", "method": "onData", "data": "Madan Mohan"}')
>>> p.action
출력: u'print'
>>> 페이지120
출력: u'on Data'
pydantic은 python 3.6+ 프로젝트에서 점점 더 인기 있는 라이브러리입니다.주로 유형 힌트를 이용한 데이터 검증 및 설정 관리를 합니다.
다양한 유형을 사용하는 기본적인 예:
from pydantic import BaseModel
class ClassicBar(BaseModel):
count_drinks: int
is_open: bool
data = {'count_drinks': '226', 'is_open': 'False'}
cb = ClassicBar(**data)
>>> cb
ClassicBar(count_drinks=226, is_open=False)
내가 lib를 좋아하는 이유는 공짜로 많은 좋은 것들을 얻을 수 있다는 거야
>>> cb.json()
'{"count_drinks": 226, "is_open": false}'
>>> cb.dict()
{'count_drinks': 226, 'is_open': False}
예를 들어 잘못된 json이 발생했을 때 또는 예상한 json이 아닌 오류를 검출할 수 있도록 필드에 대한 체크를 추가하고 싶기 때문에 namedtuples를 사용했습니다.
from collections import namedtuple
payload = namedtuple('payload', ['action', 'method', 'data'])
def deserialize_payload(json):
kwargs = dict([(field, json[field]) for field in payload._fields])
return payload(**kwargs)
해석하고 있는 json이 해석하고 싶은 것과 일치하지 않는 경우, 좋은 에러가 발생합니다.
>>> json = {"action":"print","method":"onData","data":"Madan Mohan"}
>>> deserialize_payload(json)
payload(action='print', method='onData', data='Madan Mohan')
>>> badjson = {"error":"404","info":"page not found"}
>>> deserialize_payload(badjson)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in deserialize_payload
KeyError: 'action'
중첩된 '{"parent":{"child":{"name":"henry"}}}'
튜플이나 더 가능한 할 수 .
Person = namedtuple("Person", ['parent'])
Parent = namedtuple("Parent", ['child'])
Child = namedtuple('Child', ['name'])
def deserialize_json_to_namedtuple(json, namedtuple):
return namedtuple(**dict([(field, json[field]) for field in namedtuple._fields]))
def deserialize_person(json):
json['parent']['child'] = deserialize_json_to_namedtuple(json['parent']['child'], Child)
json['parent'] = deserialize_json_to_namedtuple(json['parent'], Parent)
person = deserialize_json_to_namedtuple(json, Person)
return person
너에게 주는
>>> deserialize_person({"parent":{"child":{"name":"henry"}}})
Person(parent=Parent(child=Child(name='henry')))
>>> deserialize_person({"error":"404","info":"page not found"})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in deserialize_person
KeyError: 'parent'
또 다른 방법은 json 문자열을 단순히 dict로 오브젝트 컨스트럭터에 전달하는 것입니다.예를 들어 오브젝트는 다음과 같습니다.
class Payload(object):
def __init__(self, action, method, data, *args, **kwargs):
self.action = action
self.method = method
self.data = data
그리고 다음 두 줄의 python 코드가 그것을 구성합니다.
j = json.loads(yourJsonString)
payload = Payload(**j)
기본적으로 먼저 json 문자열에서 범용 json 개체를 만듭니다.그런 다음 일반 json 개체를 dict로 Payload 클래스의 컨스트럭터에 전달합니다.Payload 클래스의 컨스트럭터는 dict를 키워드 인수로 해석하고 모든 적절한 필드를 설정합니다.
오브젝트 작성 전용 인코더를 지정할 수 있습니다.http://docs.python.org/2/library/json.html
import json
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, complex):
return {"real": obj.real,
"imag": obj.imag,
"__class__": "complex"}
return json.JSONEncoder.default(self, obj)
print json.dumps(2 + 1j, cls=ComplexEncoder)
알렉스의 답변은 우리에게 좋은 기술을 알려주지만, 그가 제공한 구현은 중첩된 개체가 있을 때 문제에 부딪힙니다.
class more_info
string status
class payload
string action
string method
string data
class more_info
다음 코드를 사용합니다.
def as_more_info(dct):
return MoreInfo(dct['status'])
def as_payload(dct):
return Payload(dct['action'], dct['method'], dct['data'], as_more_info(dct['more_info']))
payload = json.loads(message, object_hook = as_payload)
payload.more_info
의 예로서도 취급된다.payload
해석 에러가 발생합니다.
공식 문서:
object_hook은 임의의 오브젝트 리터럴 디코딩 결과(dict)로 호출되는 옵션 함수입니다.dict 대신 object_hook 반환값이 사용됩니다.
그 때문에, 이하의 솔루션을 제안하고 싶습니다.
class MoreInfo(object):
def __init__(self, status):
self.status = status
@staticmethod
def fromJson(mapping):
if mapping is None:
return None
return MoreInfo(
mapping.get('status')
)
class Payload(object):
def __init__(self, action, method, data, more_info):
self.action = action
self.method = method
self.data = data
self.more_info = more_info
@staticmethod
def fromJson(mapping):
if mapping is None:
return None
return Payload(
mapping.get('action'),
mapping.get('method'),
mapping.get('data'),
MoreInfo.fromJson(mapping.get('more_info'))
)
import json
def toJson(obj, **kwargs):
return json.dumps(obj, default=lambda j: j.__dict__, **kwargs)
def fromJson(msg, cls, **kwargs):
return cls.fromJson(json.loads(msg, **kwargs))
info = MoreInfo('ok')
payload = Payload('print', 'onData', 'better_solution', info)
pl_json = toJson(payload)
l1 = fromJson(pl_json, Payload)
json 문자열을 개체로 역직렬화하는 방법은 여러 가지가 있습니다.위의 모든 방법을 사용할 수 있지만 중복된 키 문제를 방지하거나 중첩된 개체를 직렬화/비직렬화하는 것을 방지하기 위해 라이브러리를 사용할 것을 권장합니다.
Pykson은 Python용 JSON Serializer 및 Diserializer입니다.이것에 의해서, 실현을 지원합니다.Payload 클래스 모델을 JsonObject로 정의한 다음 Pikson을 사용하여 json 문자열을 개체로 변환하면 됩니다.
from pykson import Pykson, JsonObject, StringField
class Payload(pykson.JsonObject):
action = StringField()
method = StringField()
data = StringField()
json_text = '{"action":"print","method":"onData","data":"Madan Mohan"}'
payload = Pykson.from_json(json_text, Payload)
언급URL : https://stackoverflow.com/questions/15476983/deserialize-a-json-string-to-an-object-in-python
'source' 카테고리의 다른 글
@JsonProperty 필드 및 getter/setter의 주석 (0) | 2023.02.18 |
---|---|
React useState() 후크를 사용한 상태 개체 업데이트 및 병합 (0) | 2023.02.16 |
Postgre 저장 방법Spring Boot + JPA를 사용한SQL jsonb? (0) | 2023.02.16 |
MongoDB GUI 클라이언트(크로스 플랫폼 또는 Linux) (0) | 2023.02.16 |
오류: ORA-01704: 문자열 리터럴이 너무 깁니다. (0) | 2023.02.16 |