programing

JSON에서 중첩된 python 개체를 인코딩하는 중

newstyles 2023. 3. 10. 21:19

JSON에서 중첩된 python 개체를 인코딩하는 중

오브젝트를 JSON으로 인코딩하고 싶다.하지만 문자열이 빠져나가지 않고서는 어떻게 출력을 낼 수 있는지 알 수 없습니다.

import json

class Abc:
    def __init__(self):
        self.name="abc name"
    def toJSON(self):
        return json.dumps(self.__dict__, cls=ComplexEncoder)

class Doc:
    def __init__(self):
        self.abc=Abc()
    def toJSON(self):
        return json.dumps(self.__dict__, cls=ComplexEncoder)

class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Abc) or isinstance(obj, Doc):
            return obj.toJSON()
        else:
            return json.JSONEncoder.default(self, obj)

doc=Doc()
print doc.toJSON()

그 결과 (덤프가 문자열 표현을 반환하기 때문에가 이스케이프됩니다)

{"abc": "{\"name\": \"abc name\"}"}

나는 조금 다른 것을 원한다.예상되는 결과는

{"abc": {"name": "abc name"}"}

하지만 어떻게 해야 할지...힌트 있나요?

잘 부탁드립니다.

다른 중첩된 오브젝트와 당신의 조언이 포함된 이전 샘플:

import json

class Identity:
    def __init__(self):
        self.name="abc name"
        self.first="abc first"
        self.addr=Addr()
    def reprJSON(self):
        return dict(name=self.name, firstname=self.first, address=self.addr) 

class Addr:
    def __init__(self):
        self.street="sesame street"
        self.zip="13000"
    def reprJSON(self):
        return dict(street=self.street, zip=self.zip) 

class Doc:
    def __init__(self):
        self.identity=Identity()
        self.data="all data"
    def reprJSON(self):
        return dict(id=self.identity, data=self.data) 

class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj,'reprJSON'):
            return obj.reprJSON()
        else:
            return json.JSONEncoder.default(self, obj)

doc=Doc()
print "Str representation"
print doc.reprJSON()
print "Full JSON"
print json.dumps(doc.reprJSON(), cls=ComplexEncoder)
print "Partial JSON"
print json.dumps(doc.identity.addr.reprJSON(), cls=ComplexEncoder)

는 예상된 결과를 생성합니다.

Str representation
{'data': 'all data', 'id': <__main__.Identity instance at 0x1005317e8>}
Full JSON
{"data": "all data", "id": {"name": "abc name", "firstname": "abc first", "address": {"street": "sesame street", "zip": "13000"}}}
Partial JSON
{"street": "sesame street", "zip": "13000"}

감사해요.

따라서 JSON 모듈에 JSON 값을 전달하면 JSON 값의 다른 문자열로 인코딩됩니다.

더 큰 문제는 당신이 이걸 너무 복잡하게 만들고 있다는 거예요.

Python과 JavaScript 사이의 JSON datetime을 바탕으로 다음과 같은 것을 선택하겠습니다.

import json

class Abc:
    def __init__(self):
        self.name="abc name"
    def jsonable(self):
        return self.name

class Doc:
    def __init__(self):
        self.abc=Abc()
    def jsonable(self):
        return self.__dict__

def ComplexHandler(Obj):
    if hasattr(Obj, 'jsonable'):
        return Obj.jsonable()
    else:
        raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(Obj), repr(Obj))

doc=Doc()
print json.dumps(doc, default=ComplexHandler)

다음과 같은 이점이 있습니다.

~$ python nestjson.py 
{"abc": "abc name"}
~$ 

보다 깔끔하게, 보다 깔끔하게, 보다 안전하게(특히, 잡는 것만으로) 할 수 있습니다.__dict__일반적으로 외부 디버깅/트러블 슈팅에서는 권장되지 않지만, 요점을 이해시킬 수 있을 것입니다.기본적으로 트리의 각 "노드"에서 json 호환 객체(단순 문자열, 숫자, 목록 또는 딕트)를 가져오는 방법만 있으면 됩니다.이 오브젝트는 이미 JSON 시리얼화된 오브젝트일 수 없습니다.이러한 오브젝트를 실행하고 있습니다.

Fred Laurent의 답변에서처럼 코드가 반복되지 않도록 하기 위해 나는 오버로드했다.__iter__()방법은 다음과 같습니다.또한 datetime 및 decimal 요소, datetime 및 decimal 요소도 dict()를 사용하여 'jsonize'할 수 있습니다.

import datetime
import decimal


class Jsonable(object):
    def __iter__(self):
        for attr, value in self.__dict__.iteritems():
            if isinstance(value, datetime.datetime):
                iso = value.isoformat()
                yield attr, iso
            elif isinstance(value, decimal.Decimal):
                yield attr, str(value)
            elif(hasattr(value, '__iter__')):
                if(hasattr(value, 'pop')):
                    a = []
                    for subval in value:
                        if(hasattr(subval, '__iter__')):
                            a.append(dict(subval))
                        else:
                            a.append(subval)
                    yield attr, a
                else:
                    yield attr, dict(value)
            else:
                yield attr, value

class Identity(Jsonable):
    def __init__(self):
        self.name="abc name"
        self.first="abc first"
        self.addr=Addr()

class Addr(Jsonable):
    def __init__(self):
        self.street="sesame street"
        self.zip="13000"

class Doc(Jsonable):
    def __init__(self):
        self.identity=Identity()
        self.data="all data"


def main():
    doc=Doc()
    print "-Dictionary- \n"
    print dict(doc)
    print "\n-JSON- \n"
    print json.dumps(dict(doc), sort_keys=True, indent=4)

if __name__ == '__main__':
    main()

출력:

-Dictionary- 

{'data': 'all data', 'identity': {'first': 'abc first', 'addr': {'street': 'sesame street', 'zip': '13000'}, 'name': 'abc name'}}

-JSON- 

{
    "data": "all data", 
    "identity": {
        "addr": {
            "street": "sesame street", 
            "zip": "13000"
        }, 
        "first": "abc first", 
        "name": "abc name"
    }
}

도움이 됐으면 좋겠다!감사해요.

다른 모든 솔루션은 효과가 있다고 생각되지만, 실제로는 보일러 플레이트 코드가 많이 포함되어 있는 것을 알 수 있습니다.목표는 네스트된 비단뱀 오브젝트만 인코딩하는 것입니다.

기사에서 당신이 요청한 것과 정확히 일치하지만 보일러 플레이트 코드가 없는 우아한 해결책을 찾았습니다.디시리얼라이제이션 부품도 무료로 사용할 수 있기 때문에 먼저 정확한 질문에 대한 해결책을 보여준 후 디시리얼라이제이션이 작동하는 더 깨끗한 버전을 알려드리겠습니다.

질문에 대한 정확한 해결 방법

import json


class Abc(object):
    def __init__(self):
        self.name = "abc name"


class Doc(object):
    def __init__(self):
        self.abc = Abc()


doc = Doc()

# Serialization
json_data = json.dumps(doc, default=lambda o: o.__dict__)
print(json_data)

그러면 원하는 위치에 정확하게 출력됩니다.

{"abc": {"name": "abc name"}}

시리얼화와 시리얼화를 가능하게 하는 보다 우아한 솔루션

import json


class Abc(object):
    def __init__(self, name: str):
        self.name = name


class Doc(object):
    def __init__(self, abc):
        self.abc = abc


abc = Abc("abc name")
doc = Doc(abc)

# Serialization
json_data = json.dumps(doc, default=lambda o: o.__dict__)
print(json_data)

# De-serialization
decoded_doc = Doc(**json.loads(json_data))
print(decoded_doc)
print(vars(decoded_doc))

다음과 같이 출력됩니다.

{"abc": {"name": "abc name"}}
<__main__.Doc object at 0x7ff75366f250>
{'abc': {'name': 'abc name'}}

기본 람다 함수를 합니다.json_data = json.dumps(doc, default=lambda o: o.__dict__).

나는 이것을 댓글로 추가하지 못하고 답변으로 추가하지 못했다.프레드의 최종 샘플은 나에게 유용했다.jsonpickle이 이렇게 한다고 들었습니다만, 모듈을 올바르게 설치하고 실행할 수 없었습니다.그래서 여기 코드를 사용했어.사소한 수정이지만, 몇몇 오브젝트에 손으로 추가해야 할 변수가 너무 많았습니다.이 작은 루프는 다음과 같은 것을 단순화합니다.

def reprJSON(self):
    d = dict()
    for a, v in self.__dict__.items():
        if (hasattr(v, "reprJSON")):
            d[a] = v.reprJSON()
        else:
            d[a] = v
    return d

서브클래스가 너무 많아 수동으로 인코딩할 수 없는 오브젝트에서 사용할 수 있습니다.또는 모든 클래스의 도우미가 될 수 있습니다.이것은 다른 클래스를 포함한 멤버 배열의 완전한 JSON 프레젠테이션에도 유효합니다(물론 reprJSON()을 실장하고 있는 한).

좀 더 복잡한 연재에는 2022년에 출판된 jsons를 사용합니다.

  • Python 개체를 dicts 또는 (JSON) 문자열로 변환한 후 되돌리기

  • 개체를 변경할 필요가 없습니다.

  • 커스터마이즈와 확장이 용이함

  • 데이터 클래스, 특성 및 POPO와 함께 작동

      pip install jsons
      class Person:
            name:str
            birthday:datetime
    
      personObject = Person("Tony", date_of_birth)
    
      import jsons
      json_data = jsons.dumps(personObject, indent=4)
    

찾으시는 제품은 다음과 같습니다.https://github.com/jsonpickle/jsonpickle

Python 객체의 중첩된 직렬화를 수행하며, 쉽게 확장하여 사용자 지정 유형을 직렬화할 수 있습니다.

언급URL : https://stackoverflow.com/questions/5160077/encoding-nested-python-object-in-json