JSON 데이터를 Python 객체로 변환하는 방법


281

Python을 사용하여 JSON 데이터를 Python 객체로 변환하고 싶습니다.

데이터베이스에 저장하려는 Facebook API에서 JSON 데이터 객체를받습니다.

Django (Python)의 현재보기 ( request.POSTJSON 포함) :

response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
  • 이것은 잘 작동하지만 복잡한 JSON 데이터 객체를 어떻게 처리합니까?

  • 이 JSON 객체를 사용하기 쉽도록 Python 객체로 변환 할 수 있다면 훨씬 좋지 않을까요?


일반적으로 JSON은 바닐라 목록 또는 딕 트로 변환됩니다. 너가 원하는게 그거야? 아니면 JSON을 직접 사용자 정의 유형으로 변환하고 싶습니까?
Shakakai

"."를 사용하여 액세스 할 수있는 개체로 변환하고 싶습니다. . 위의 예에서와 같이-> reponse.name, response.education.id 등 ....
Sai Krishna

44
dicts를 사용 하는 것은 객체 지향 프로그래밍을 수행하는 약한 소스 방법입니다. 사전은 코드 독자에게 기대치를 전달하는 매우 나쁜 방법입니다. 사전을 사용하면 일부 사전 키-값 쌍이 필요하고 다른 사전 키는 필요하지 않은 것을 명확하고 재사용 가능하게 어떻게 지정할 수 있습니까? 주어진 값이 허용 가능한 범위 또는 설정에 있는지 확인하는 것은 어떻습니까? 작업중인 객체 유형 (일명 메서드)에 특정한 함수는 어떻습니까? 사전은 편리하고 다재다능하지만 너무 많은 개발자는 파이썬이 이유로 객체 지향 언어를 잊어 버린 것처럼 행동합니다.
스튜

1
이것에 대한 파이썬 라이브러리가 github.com/jsonpickle/jsonpickle이 (답부터 주석하는 것은 스레드에서 너무 아래이고 도달 할 수 실 거예요.)
최고의 소원

답변:


355

namedtupleand를 사용하여 한 줄로 할 수 있습니다 object_hook.

import json
from collections import namedtuple

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id

또는 이것을 쉽게 재사용하려면 :

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)

x = json2obj(data)

속성 이름이 좋지 않은 키를 처리하려면 namedtuplerename매개 변수를 확인하십시오 .


8
이것은 값 오류가 발생할 수 있습니다, ValueError를이 : 유형 이름과 필드 이름은 숫자로 시작할 수 없습니다 : '123'
PvdL

3
파이썬 초보자에게는 보안이 문제가 될 때도 이것이 저장인지 관심이 있습니다.
benjist

8
이것은 새로운 만들고 다른 클래스마다 구문 분석하는 동안 오른쪽 JSON 개체를 발생을?
fikr4n

2
흥미 롭군 나는 같은 순서에 의존 d.keys()하고 d.values()반복하는 것이 보장되지 않는다고 생각 했지만 잘못되었습니다. 문서는 말한다 : "키 값과 항목 뷰가 사전에 전혀 개입의 수정을 통해 반복하는 경우, 항목의 순서가 직접 것입니다 해당합니다.". 작은 지역 코드 블록에 대해 알아두면 좋습니다. 그러한 의존성 코드를 관리자에게 명시 적으로 경고하기 위해 주석을 추가하고 싶습니다.
cfi

1
나는 훌륭한 범용 역 동작을 알지 못한다. 명명 된 튜플은 모두 다음을 사용하여 받아쓰기로 설정할 수 있습니다.x._asdict() .
DS.

127

모듈 문서 에서 JSON 객체 디코딩 전문화 섹션을 확인하십시오 . 이를 사용하여 JSON 객체를 특정 Python 유형으로 디코딩 할 수 있습니다.json

예를 들면 다음과 같습니다.

class User(object):
    def __init__(self, name, username):
        self.name = name
        self.username = username

import json
def object_decoder(obj):
    if '__type__' in obj and obj['__type__'] == 'User':
        return User(obj['name'], obj['username'])
    return obj

json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}',
           object_hook=object_decoder)

print type(User)  # -> <type 'type'>

최신 정보

json 모듈을 통해 사전의 데이터에 액세스하려면 다음을 수행하십시오.

user = json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}')
print user['name']
print user['username']

일반 사전처럼.


1
이봐, 나는 방금 읽고 있었고 사전이 완전히 할 것이라는 것을 깨달았지만 JSON 객체를 사전으로 변환하는 방법과 사전 에서이 데이터에 어떻게 액세스합니까?
사이 크리슈나

굉장히 분명합니다.이 객체가 있으면- '{education': { 'name1': 456, 'name2': 567}} 한 가지 더 작은 것을 알고 싶었습니다.이 데이터에 어떻게 액세스합니까?
사이 크리슈나

그냥 topLevelData [ 'education'] [ 'name1'] ==> 456 일 것입니다.
Shakakai

1
@ 벤 : 귀하의 의견이 부적절하다고 생각합니다. 여기에있는 모든 대답 중 현재 수업을 올바르게하는 것은 유일합니다. 의미 : 그것은 한 번의 작업이며 결과는 올바른 유형을 사용합니다. 피클 자체는 JSON (이진 대 텍스트 응답)과 다른 애플리케이션을위한 것이며 jsonpickle은 비표준 라이브러리입니다. 난 당신이 객체 후크 위 파스 트리를 제공하지 않는 표준 JSON LIB 것을 문제 해결 방식을 볼 수 싶네
CFI

나는 @Ben에 동의해야합니다. 이것은 정말 나쁜 해결책입니다. 전혀 확장 할 수 없습니다. 필드 이름을 문자열 및 필드로 유지해야합니다. 필드를 리팩터링하려면 디코딩이 실패합니다 (물론 이미 직렬화 된 데이터는 더 이상 관련이 없습니다). 동일한 개념은 이미 잘 구현되어 jsonpickle
guyarad

99

이것은 코드 골프가 아니지만 types.SimpleNamespaceJSON 객체의 컨테이너로 사용 하는 가장 짧은 트릭 입니다.

최고의 namedtuple솔루션과 비교하면 다음 과 같습니다.

  • 각 객체에 대한 클래스를 만들지 않으므로 더 빠르거나 작을 수 있습니다.
  • 더 짧은
  • rename유효한 식별자 (용도가없는 키에 대한 옵션이없고, 아마 동일한 제한 setattr내부적으로)

예:

from __future__ import print_function
import json

try:
    from types import SimpleNamespace as Namespace
except ImportError:
    # Python 2.x fallback
    from argparse import Namespace

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

x = json.loads(data, object_hook=lambda d: Namespace(**d))

print (x.name, x.hometown.name, x.hometown.id)

2
그런데 직렬화 라이브러리 Marshmallow는 @post_load데코레이터 와 비슷한 기능을 제공합니다 . marshmallow.readthedocs.io/en/latest/…
Taylor Edmiston

3
argparse에 대한 종속성을 피하려면 : argparse와 수입 대체 from types import SimpleNamespace및 사용 :x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
maxschlepzig

8
이것은 가장 우아한 솔루션이며 맨 위에 있어야합니다.
ScalaWilliam

4
Python 3.x에서 실행할 때 @maxschlepzig의 솔루션을 사용하도록 편집되었습니다 ( types.SimpleNamespace불행히도 2.7에는 존재하지 않음).
Dan Lenski

1
print_function?
chwi

90

당신은 이것을 시도 할 수 있습니다 :

class User(object):
    def __init__(self, name, username, *args, **kwargs):
        self.name = name
        self.username = username

import json
j = json.loads(your_json)
u = User(**j)

새 객체를 만들고 매개 변수를 맵으로 전달하면됩니다.


1
TypeError : 'User'개체를 설명 할 수 없음
Mahdi

1
이것은 정답입니다. 나를 위해 다른 모든 것보다 훨씬 간단하게 광고했습니다.
Izik

나는 * args, ** kwargs를 사용하지 않았지만 솔루션은 효과가있었습니다.
Malkaviano

1
User (** j)는 name 및 username 매개 변수가 누락되어 있으며 dict 는 어떻게 초기화됩니까?
Aaron Stainback '

40

빠르고 더러운 json pickle 대안이 있습니다.

import json

class User:
    def __init__(self, name, username):
        self.name = name
        self.username = username

    def to_json(self):
        return json.dumps(self.__dict__)

    @classmethod
    def from_json(cls, json_str):
        json_dict = json.loads(json_str)
        return cls(**json_dict)

# example usage
User("tbrown", "Tom Brown").to_json()
User.from_json(User("tbrown", "Tom Brown").to_json()).to_json()

1
이것은 좋은 접근 방식이 아닙니다. 처음에는 to_json과 from_json을 수업에 배치해서는 안됩니다. 초반에는 중첩 클래스에는 작동하지 않습니다.
쥬라기

17

복잡한 객체의 경우 JSON Pickle을 사용할 수 있습니다.

임의의 객체 그래프를 JSON으로 직렬화하기위한 Python 라이브러리 거의 모든 Python 객체를 사용하여 객체를 JSON으로 바꿀 수 있습니다. 또한 객체를 다시 파이썬으로 재구성 할 수 있습니다.


6
jsonstruct 가 더 낫다고 생각 합니다. jsonstruct originally a fork of jsonpickle (Thanks guys!). The key difference between this library and jsonpickle is that during deserialization, jsonpickle requires Python types to be recorded as part of the JSON. This library intends to remove this requirement, instead, requires a class to be passed in as an argument so that its definition can be inspected. It will then return an instance of the given class. This approach is similar to how Jackson (of Java) works.
Abhishek Gupta

3
jsonstruct의 문제점은 유지되지 않는 것으로 보이며 (사실 포기 된 것처럼 보임)와 같은 객체 목록을 변환하지 못한다는 것 '[{"name":"object1"},{"name":"object2"}]'입니다. jsonpickle도 잘 처리하지 못합니다.
LS

1
이 답변이 더 많은 표를 얻지 못하는 이유를 모르겠습니다. 대부분의 다른 솔루션은 꽤 있습니다. 누군가 JSON de / serialization을위한 훌륭한 라이브러리를 개발했습니다. 왜 사용하지 않습니까? 또한 목록에서 잘 작동하는 것 같습니다. @LS의 문제는 무엇입니까?
guyarad

1
@guyarad, 문제는 다음과 같습니다. x = jsonpickle.decode ( '[{ "name": "object1"}, { "name": "object2"}]') 사전 목록 ([{ 'name': ' object1 '}, {'name ':'object2 '}]), 속성 (x [0] .name =='object1 ')이있는 객체 목록이 아닙니다. 이는 원래 질문에 필요한 것입니다. 그것을 얻기 위해 eddygeek이 제안한 object_hook / Namespace 접근 방식을 사용했지만 ubershmekel의 빠른 / 더러운 접근 방식도 좋아 보입니다. jsonpickle의 set_encoder_options () (undocumented!)와 함께 object_hook을 사용할 수 있다고 생각하지만 기본 json 모듈보다 더 많은 코드가 필요합니다. 나는 틀린 것으로 증명되고 싶다!
LS

@LS 당신이 입력을 제어 할 수 없다면, 실제로 OP가 요구 한 것입니다. 두 솔루션 모두 "귀엽다".
guyarad

12

Python 3.5 이상을 사용하는 경우 jsons일반 오래된 Python 객체로 직렬화 및 역 직렬화하는 데 사용할 수 있습니다 .

import jsons

response = request.POST

# You'll need your class attributes to match your dict keys, so in your case do:
response['id'] = response.pop('user_id')

# Then you can load that dict into your class:
user = jsons.load(response, FbApiUser)

user.save()

더 우아함을 위해 FbApiUser상속받을 수도 있습니다 jsons.JsonSerializable.

user = FbApiUser.from_json(response)

이 예제는 클래스가 문자열, 정수, 목록, 날짜 시간 등과 같은 Python 기본 유형으로 구성된 경우 작동합니다. jsonslib에는 사용자 정의 유형에 대한 유형 힌트가 필요합니다.


7

python 3.6 이상을 사용하는 경우 marshmallow-dataclass를 사용할 수 있습니다 . 위에 나열된 모든 솔루션과 반대로 간단하고 유형이 안전합니다.

from marshmallow_dataclass import dataclass

@dataclass
class User:
    name: str

user, err = User.Schema().load({"name": "Ramirez"})

TypeError: make_data_class() got an unexpected keyword argument 'many'
JOhn

@ 존 : 당신의 재현성 테스트 케이스에 문제를 열어야합니다 github.com/lovasoa/marshmallow_dataclass/issues
lovasoa

6

로바 소아의 정답을 향상시킵니다.

당신은 파이썬 3.6 이상을 사용하는 경우 사용할 수 있습니다
pip install marshmallow-enum
pip install marshmallow-dataclass

간단하고 안전합니다.

문자열을 JSON으로 변환하거나 그 반대로 변환 할 수 있습니다.

객체에서 문자열 Json으로 :

    from marshmallow_dataclass import dataclass
    user = User("Danilo","50","RedBull",15,OrderStatus.CREATED)
    user_json = User.Schema().dumps(user)
    user_json_str = user_json.data

String Json에서 Object로 :

    json_str = '{"name":"Danilo", "orderId":"50", "productName":"RedBull", "quantity":15, "status":"Created"}'
    user, err = User.Schema().loads(json_str)
    print(user,flush=True)

클래스 정의 :

class OrderStatus(Enum):
    CREATED = 'Created'
    PENDING = 'Pending'
    CONFIRMED = 'Confirmed'
    FAILED = 'Failed'

@dataclass
class User:
    def __init__(self, name, orderId, productName, quantity, status):
        self.name = name
        self.orderId = orderId
        self.productName = productName
        self.quantity = quantity
        self.status = status

    name: str
    orderId: str
    productName: str
    quantity: int
    status: OrderStatus

1
생성자가 필요하지 않습니다. init = True를 데이터 클래스에 전달하면 좋습니다.
Josef Korbel

5

두 파이썬 유형 사이에서 복잡한 변환을 수행하는 데 도움이되는 any2any 라는 작은 (직렬화) 직렬화 프레임 워크를 작성했습니다 .

귀하의 경우에는 사전에서 (으로 얻은 json.loads) 사전 response.education ; response.name에서 중첩 된 구조 response.education.id등 의 복잡한 객체 로 변환하려고한다고 생각합니다 . 그래서이 프레임 워크가 만들어진 것입니다. 설명서는 아직 훌륭하지는 않지만를 사용 any2any.simple.MappingToObject하면 매우 쉽게 할 수 있습니다. 도움이 필요한지 물어보십시오.


Sebpiq은 any2any를 설치했으며 원하는 메소드 호출 순서를 이해하는 데 어려움을 겪고 있습니다. 각 키의 속성을 사용하여 사전을 Python 객체로 변환하는 간단한 예를 들어 주시겠습니까?
sansjoe

안녕하세요 @sansjoe! pypi에서 설치 한 경우 버전이 완전히 오래된 것입니다. 몇 주 전에 리팩토링을 완료했습니다. github 버전을 사용해야합니다 (적절한 릴리스가 필요합니다!)
sebpiq

github가 pypy에서 설치한다고 말했기 때문에 pypy에서 설치했습니다. ! 또한, 그것은 내가 상점 버그 리포트를 제출 :( 작동하지 않았다 .. pypy 전에 날짜 개월 밖으로했다 github.com/sebpiq/any2any/issues/11
sneilan

4

아무도 나와 같은 답변을 제공하지 않았으므로 여기에 게시하겠습니다.

그것은 쉽게 JSON 사이에 앞뒤로 변환 할 수있는 강력한 클래스 strdict나는에서 복사 한 것을 다른 질문에 대한 내 대답 :

import json

class PyJSON(object):
    def __init__(self, d):
        if type(d) is str:
            d = json.loads(d)

        self.from_dict(d)

    def from_dict(self, d):
        self.__dict__ = {}
        for key, value in d.items():
            if type(value) is dict:
                value = PyJSON(value)
            self.__dict__[key] = value

    def to_dict(self):
        d = {}
        for key, value in self.__dict__.items():
            if type(value) is PyJSON:
                value = value.to_dict()
            d[key] = value
        return d

    def __repr__(self):
        return str(self.to_dict())

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, key):
        return self.__dict__[key]

json_str = """... json string ..."""

py_json = PyJSON(json_str)

2

파일에서로드하기 위해 @DS 응답을 약간 수정했습니다.

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def load_data(file_name):
  with open(file_name, 'r') as file_data:
    return file_data.read().replace('\n', '')
def json2obj(file_name): return json.loads(load_data(file_name), object_hook=_json_object_hook)

한 가지 : 앞의 숫자가있는 항목을로드 할 수 없습니다. 이처럼 :

{
  "1_first_item": {
    "A": "1",
    "B": "2"
  }
}

"1_first_item"은 유효한 파이썬 필드 이름이 아니기 때문입니다.


2

솔루션을 검색하는 동안이 블로그 게시물을 우연히 발견했습니다 : https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/

이전 답변에서 설명한 것과 동일한 기술을 사용하지만 데코레이터를 사용합니다. 내가 유용하다고 생각한 또 다른 것은 직렬화 해제가 끝날 때 유형이 지정된 객체를 반환한다는 사실입니다.

class JsonConvert(object):
    class_mappings = {}

    @classmethod
    def class_mapper(cls, d):
        for keys, cls in clsself.mappings.items():
            if keys.issuperset(d.keys()):   # are all required arguments present?
                return cls(**d)
        else:
            # Raise exception instead of silently returning None
            raise ValueError('Unable to find a matching class for object: {!s}'.format(d))

    @classmethod
    def complex_handler(cls, Obj):
        if hasattr(Obj, '__dict__'):
            return Obj.__dict__
        else:
            raise TypeError('Object of type %s with value of %s is not JSON serializable' % (type(Obj), repr(Obj)))

    @classmethod
    def register(cls, claz):
        clsself.mappings[frozenset(tuple([attr for attr,val in cls().__dict__.items()]))] = cls
        return cls

    @classmethod
    def to_json(cls, obj):
        return json.dumps(obj.__dict__, default=cls.complex_handler, indent=4)

    @classmethod
    def from_json(cls, json_str):
        return json.loads(json_str, object_hook=cls.class_mapper)

용법:

@JsonConvert.register
class Employee(object):
    def __init__(self, Name:int=None, Age:int=None):
        self.Name = Name
        self.Age = Age
        return

@JsonConvert.register
class Company(object):
    def __init__(self, Name:str="", Employees:[Employee]=None):
        self.Name = Name
        self.Employees = [] if Employees is None else Employees
        return

company = Company("Contonso")
company.Employees.append(Employee("Werner", 38))
company.Employees.append(Employee("Mary"))

as_json = JsonConvert.to_json(company)
from_json = JsonConvert.from_json(as_json)
as_json_from_json = JsonConvert.to_json(from_json)

assert(as_json_from_json == as_json)

print(as_json_from_json)

2

DS의 대답을 약간 확장하면 객체를 변경 가능 해야하는 경우 (namedtuple은 아닙니다) namedtuple 대신 레코드 클래스 라이브러리를 사용할 수 있습니다 .

import json
from recordclass import recordclass

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse into a mutable object
x = json.loads(data, object_hook=lambda d: recordclass('X', d.keys())(*d.values()))

수정 된 객체는 simplejson을 사용하여 매우 쉽게 json으로 다시 변환 할 수 있습니다 .

x.name = "John Doe"
new_json = simplejson.dumps(x)

1

Python 3.6 이상을 사용하는 경우 정적 형식의 데이터 구조를위한 경량 모듈 인 squema를 살펴볼 수 있습니다 . 추가 작업없이 간단한 데이터 유효성 검사, 변환 및 직렬화를 제공하면서 동시에 코드를 쉽게 읽을 수 있습니다. 명명 된 튜플 및 데이터 클래스에 대한보다 정교하고 의견이 많은 대안으로 생각할 수 있습니다. 사용 방법은 다음과 같습니다.

from uuid import UUID
from squema import Squema


class FbApiUser(Squema):
    id: UUID
    age: int
    name: str

    def save(self):
        pass


user = FbApiUser(**json.loads(response))
user.save()

이것은 또한 JVM 언어 방식과 유사합니다.
javadba

1

와 함께 작업하고 recordclass.RecordClass중첩 된 객체를 지원하며 json 직렬화 및 json deserialization 모두에서 작동 하는 솔루션을 찾고있었습니다 .

DS의 답변을 확장하고 BeneStr의 솔루션을 확장하면서 다음과 같이 작동하는 것으로 나타났습니다.

암호:

import json
import recordclass

class NestedRec(recordclass.RecordClass):
    a : int = 0
    b : int = 0

class ExampleRec(recordclass.RecordClass):
    x : int       = None
    y : int       = None
    nested : NestedRec = NestedRec()

class JsonSerializer:
    @staticmethod
    def dumps(obj, ensure_ascii=True, indent=None, sort_keys=False):
        return json.dumps(obj, default=JsonSerializer.__obj_to_dict, ensure_ascii=ensure_ascii, indent=indent, sort_keys=sort_keys)

    @staticmethod
    def loads(s, klass):
        return JsonSerializer.__dict_to_obj(klass, json.loads(s))

    @staticmethod
    def __obj_to_dict(obj):
        if hasattr(obj, "_asdict"):
            return obj._asdict()
        else:
            return json.JSONEncoder().default(obj)

    @staticmethod
    def __dict_to_obj(klass, s_dict):
        kwargs = {
            key : JsonSerializer.__dict_to_obj(cls, s_dict[key]) if hasattr(cls,'_asdict') else s_dict[key] \
                for key,cls in klass.__annotations__.items() \
                    if s_dict is not None and key in s_dict
        }
        return klass(**kwargs)

용법:

example_0 = ExampleRec(x = 10, y = 20, nested = NestedRec( a = 30, b = 40 ) )

#Serialize to JSON

json_str = JsonSerializer.dumps(example_0)
print(json_str)
#{
#  "x": 10,
#  "y": 20,
#  "nested": {
#    "a": 30,
#    "b": 40
#  }
#}

# Deserialize from JSON
example_1 = JsonSerializer.loads(json_str, ExampleRec)
example_1.x += 1
example_1.y += 1
example_1.nested.a += 1
example_1.nested.b += 1

json_str = JsonSerializer.dumps(example_1)
print(json_str)
#{
#  "x": 11,
#  "y": 21,
#  "nested": {
#    "a": 31,
#    "b": 41
#  }
#}

1

여기에 주어진 대답은 올바른 객체 유형을 반환하지 않으므로 아래에서 이러한 메소드를 만들었습니다. 주어진 JSON에 존재하지 않는 클래스에 더 많은 필드를 추가하려고 시도하면 실패합니다.

def dict_to_class(class_name: Any, dictionary: dict) -> Any:
    instance = class_name()
    for key in dictionary.keys():
        setattr(instance, key, dictionary[key])
    return instance


def json_to_class(class_name: Any, json_string: str) -> Any:
    dict_object = json.loads(json_string)
    return dict_to_class(class_name, dict_object)

0

Python3.x

내가 아는 가장 좋은 방법은 이것입니다.
이 코드는 set ()도 처리합니다.
이 접근 방식은 클래스 확장 (두 번째 예) 만 있으면됩니다.
파일로만 처리하고 있지만 취향에 따라 동작을 쉽게 수정할 수 있습니다.

그러나 이것은 CoDec입니다.

약간의 작업으로 다른 방법으로 수업을 구성 할 수 있습니다. 기본 생성자를 인스턴스화한다고 가정 한 다음 클래스 dict를 업데이트합니다.

import json
import collections


class JsonClassSerializable(json.JSONEncoder):

    REGISTERED_CLASS = {}

    def register(ctype):
        JsonClassSerializable.REGISTERED_CLASS[ctype.__name__] = ctype

    def default(self, obj):
        if isinstance(obj, collections.Set):
            return dict(_set_object=list(obj))
        if isinstance(obj, JsonClassSerializable):
            jclass = {}
            jclass["name"] = type(obj).__name__
            jclass["dict"] = obj.__dict__
            return dict(_class_object=jclass)
        else:
            return json.JSONEncoder.default(self, obj)

    def json_to_class(self, dct):
        if '_set_object' in dct:
            return set(dct['_set_object'])
        elif '_class_object' in dct:
            cclass = dct['_class_object']
            cclass_name = cclass["name"]
            if cclass_name not in self.REGISTERED_CLASS:
                raise RuntimeError(
                    "Class {} not registered in JSON Parser"
                    .format(cclass["name"])
                )
            instance = self.REGISTERED_CLASS[cclass_name]()
            instance.__dict__ = cclass["dict"]
            return instance
        return dct

    def encode_(self, file):
        with open(file, 'w') as outfile:
            json.dump(
                self.__dict__, outfile,
                cls=JsonClassSerializable,
                indent=4,
                sort_keys=True
            )

    def decode_(self, file):
        try:
            with open(file, 'r') as infile:
                self.__dict__ = json.load(
                    infile,
                    object_hook=self.json_to_class
                )
        except FileNotFoundError:
            print("Persistence load failed "
                  "'{}' do not exists".format(file)
                  )


class C(JsonClassSerializable):

    def __init__(self):
        self.mill = "s"


JsonClassSerializable.register(C)


class B(JsonClassSerializable):

    def __init__(self):
        self.a = 1230
        self.c = C()


JsonClassSerializable.register(B)


class A(JsonClassSerializable):

    def __init__(self):
        self.a = 1
        self.b = {1, 2}
        self.c = B()

JsonClassSerializable.register(A)

A().encode_("test")
b = A()
b.decode_("test")
print(b.a)
print(b.b)
print(b.c.a)

편집하다

더 많은 연구 를 통해 메타 클래스를 사용하여 SUPERCLASS 레지스터 메소드 호출 이 필요없는 일반화 방법을 찾았습니다.

import json
import collections

REGISTERED_CLASS = {}

class MetaSerializable(type):

    def __call__(cls, *args, **kwargs):
        if cls.__name__ not in REGISTERED_CLASS:
            REGISTERED_CLASS[cls.__name__] = cls
        return super(MetaSerializable, cls).__call__(*args, **kwargs)


class JsonClassSerializable(json.JSONEncoder, metaclass=MetaSerializable):

    def default(self, obj):
        if isinstance(obj, collections.Set):
            return dict(_set_object=list(obj))
        if isinstance(obj, JsonClassSerializable):
            jclass = {}
            jclass["name"] = type(obj).__name__
            jclass["dict"] = obj.__dict__
            return dict(_class_object=jclass)
        else:
            return json.JSONEncoder.default(self, obj)

    def json_to_class(self, dct):
        if '_set_object' in dct:
            return set(dct['_set_object'])
        elif '_class_object' in dct:
            cclass = dct['_class_object']
            cclass_name = cclass["name"]
            if cclass_name not in REGISTERED_CLASS:
                raise RuntimeError(
                    "Class {} not registered in JSON Parser"
                    .format(cclass["name"])
                )
            instance = REGISTERED_CLASS[cclass_name]()
            instance.__dict__ = cclass["dict"]
            return instance
        return dct

    def encode_(self, file):
        with open(file, 'w') as outfile:
            json.dump(
                self.__dict__, outfile,
                cls=JsonClassSerializable,
                indent=4,
                sort_keys=True
            )

    def decode_(self, file):
        try:
            with open(file, 'r') as infile:
                self.__dict__ = json.load(
                    infile,
                    object_hook=self.json_to_class
                )
        except FileNotFoundError:
            print("Persistence load failed "
                  "'{}' do not exists".format(file)
                  )


class C(JsonClassSerializable):

    def __init__(self):
        self.mill = "s"


class B(JsonClassSerializable):

    def __init__(self):
        self.a = 1230
        self.c = C()


class A(JsonClassSerializable):

    def __init__(self):
        self.a = 1
        self.b = {1, 2}
        self.c = B()


A().encode_("test")
b = A()
b.decode_("test")
print(b.a)
# 1
print(b.b)
# {1, 2}
print(b.c.a)
# 1230
print(b.c.c.mill)
# s

0

당신이 사용할 수있는

x = Map(json.loads(response))
x.__class__ = MyClass

어디

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v
                    if isinstance(v, dict):
                        self[k] = Map(v)

        if kwargs:
            # for python 3 use kwargs.items()
            for k, v in kwargs.iteritems():
                self[k] = v
                if isinstance(v, dict):
                    self[k] = Map(v)

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

일반적인 미래 보장 솔루션


-5

json모듈 ( Python 2.6의 새로운 기능 ) 또는 simplejson거의 항상 설치되는 모듈을 사용하십시오 .


2
답장 주셔서 감사합니다. JSON을 디코딩하고 해당 데이터에 액세스하는 방법의 예를 게시 할 수 있습니까?
사이 크리슈나

이봐, 이제 당신은 요점을 얻었지만 어쨌든, 나는 그것을 알지 못하고 그것을 리버스 엔지니어링하지 않고하는 것을 선호합니다 : D.
Sai Krishna

1
@ Zach : 내가 링크 한 문서 맨 위에 예제가 있습니다.
Chris Morgan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.