source

JSON 세트를 시리얼화하는 방법

bestscript 2023. 2. 12. 18:06

JSON 세트를 시리얼화하는 방법

는 파이썬 파이썬을 있다.set가 포함되어 .__hash__ ★★★★★★★★★★★★★★★★★」__eq__중복이 컬렉션에 포함되지 않도록 하기 위한 메서드입니다.

.set지나가다setjson.dumps은 메 a a a a a a a method를 .TypeError.

  File "/usr/lib/python2.7/json/encoder.py", line 201, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 264, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python2.7/json/encoder.py", line 178, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: set([]) is not JSON serializable

는 내가 수 것을 .json.JSONEncoder default 「를 잘 set 은 을 해서 만들어 요?set디폴트 메서드 내에서 값을 지정한 후 인코딩을 반환합니다.이상적으로는 디폴트 메서드로 원래 인코더가 체크하는 모든 데이터 타입을 처리할 수 있도록 하고 싶다(Mongo를 데이터 소스로 사용하고 있기 때문에 날짜도 이 에러가 발생하는 것 같다.

올바른 방향으로 힌트를 주시면 감사하겠습니다.

편집:

답변 감사합니다!좀 더 정확하게 말할 걸 그랬나 봐요

이) '어느 정도'라는 한계를 .set번역되고 있습니다만, 내부 키도 문제가 되고 있습니다.

set라고 하는 것은, 입니다.__dict__단, json 인코더 내의 기본유형에 적합하지 않을 수 있는 속성값도 포함할 수 있습니다.

들어오고 있어요.set해시는 기본적으로 엔티티에 대한 고유 ID를 계산하지만, 진정한 의미의 NoSQL에서는 하위 객체가 정확히 무엇을 포함하고 있는지 알 수 없습니다.

에는 날짜 수 .starts다른 스키마에는 "비표준" 개체를 포함하는 키가 포함되지 않은 다른 스키마가 있을 수 있습니다.

은 ''밖에.JSONEncoderdefault다른 케이스를 활성화하는 방법 - 하지만 어떻게 해야 할지 잘 모르겠고 문서도 애매합니다.은 첩음음에서 반환되는 입니까?default키별로 이동하거나 개체 전체를 보는 일반적인 포함/부호만 포함합니까?이 방법은 어떻게 중첩된 값을 수용합니까?이전 질문들을 살펴봤지만, 케이스 고유의 인코딩에 대한 최선의 접근방식을 찾을 수 없는 것 같습니다(불행하게도 여기서 해야 할 것 같습니다).

「」를할 수 .list when 를 만났을 때set하다

import json
class SetEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, set):
            return list(obj)
        return json.JSONEncoder.default(self, obj)

data_str = json.dumps(set([1,2,3,4,5]), cls=SetEncoder)
print(data_str)
# Output: '[1, 2, 3, 4, 5]'

이렇게 하면 다른 종류도 탐지할 수 있습니다.목록이 실제로 세트임을 유지해야 하는 경우 사용자 지정 인코딩을 사용할 수 있습니다.return {'type':'set', 'list':list(obj)}효과가 있을지도 모릅니다.

네스트된 타입을 나타내려면 , 다음의 시리얼화를 검토해 주세요.

class Something(object):
    pass
json.dumps(set([1,2,3,4,5,Something()]), cls=SetEncoder)

이것에 의해, 다음의 에러가 발생합니다.

TypeError: <__main__.Something object at 0x1691c50> is not JSON serializable

은, 가 「」, 「」, 「」, 「」, 「」를 을 나타냅니다.list결과가 반환되어 하위의 시리얼라이저를 재귀적으로 호출합니다.여러 유형의 커스텀시리얼라이저를 추가하려면 다음 작업을 수행합니다.

class SetEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, set):
            return list(obj)
        if isinstance(obj, Something):
            return 'CustomSomethingRepresentation'
        return json.JSONEncoder.default(self, obj)
 
data_str = json.dumps(set([1,2,3,4,5,Something()]), cls=SetEncoder)
print(data_str)
# Output: '[1, 2, 3, 4, 5, "CustomSomethingRepresentation"]'

JSON 표기법에는 네이티브 데이터형(오브젝트, 배열, 문자열, 숫자, 부울 및 늘)이 몇 개밖에 없기 때문에 JSON에서 직렬화된 모든 데이터는 이러한 유형 중 하나로 표현해야 합니다.

json 모듈 문서에 나타나 있듯이 이 변환은 JSONEncoderJSONDecoder에 의해 자동으로 수행될 수 있지만, 필요한 다른 구조를 포기하게 됩니다(세트를 목록으로 변환하면 일반 목록을 복구하는 기능이 상실됩니다).dict.fromkeys(s)을 참조해 주십시오.)

보다 정교한 솔루션은 다른 네이티브 JSON 유형과 공존할 수 있는 사용자 지정 유형을 구축하는 것입니다.이를 통해 목록, 세트, 딕트, 소수점, 날짜/시간 개체 등을 포함하는 중첩 구조를 저장할 수 있습니다.

from json import dumps, loads, JSONEncoder, JSONDecoder
import pickle

class PythonObjectEncoder(JSONEncoder):
    def default(self, obj):
        try:
            return {'_python_object': pickle.dumps(obj).decode('latin-1')}
        except pickle.PickleError:
            return super().default(obj)

def as_python_object(dct):
    if '_python_object' in dct:
        return pickle.loads(dct['_python_object'].encode('latin-1'))
    return dct

다음은 목록, 받아쓰기 및 집합을 처리할 수 있음을 보여주는 샘플 세션입니다.

>>> data = [1,2,3, set(['knights', 'who', 'say', 'ni']), {'key':'value'}, Decimal('3.14')]

>>> j = dumps(data, cls=PythonObjectEncoder)

>>> loads(j, object_hook=as_python_object)
[1, 2, 3, set(['knights', 'say', 'who', 'ni']), {'key': 'value'}, Decimal('3.14')]

또는 YAML, Twisted Jelly 또는 Python의 피클 모듈과 같은 보다 범용적인 시리얼라이제이션 기술을 사용하는 것이 유용할 수 있습니다.이들 각각은 훨씬 광범위한 데이터 유형을 지원합니다.

는 커스텀인코더 를 만들 defaultmethod -인수로 할 수 .

import json

def serialize_sets(obj):
    if isinstance(obj, set):
        return list(obj)

    return obj

json_str = json.dumps(set([1,2,3]), default=serialize_sets)
print(json_str)

이 되다[1, 2, 3]Python은 Python입니다.

할 수 없는 는 「」이라는 있는 .sets, 매우 심플한(더러운) 솔루션이 있습니다.

json.dumps({"Hello World": {1, 2}}, default=tuple)

할 수 됩니다.default 그 중 하나밖에 settuple.

Raymond Hettinger의 솔루션을 python 3에 적용했습니다.

변경된 내용은 다음과 같습니다.

  • unicode를 감추다
  • 했다.defaultsuper()
  • 를 사용합니다.base64bytes 타이핑하다str (되기 때문에)bytes python 으로 변환할 수 .
from decimal import Decimal
from base64 import b64encode, b64decode
from json import dumps, loads, JSONEncoder
import pickle

class PythonObjectEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (list, dict, str, int, float, bool, type(None))):
            return super().default(obj)
        return {'_python_object': b64encode(pickle.dumps(obj)).decode('utf-8')}

def as_python_object(dct):
    if '_python_object' in dct:
        return pickle.loads(b64decode(dct['_python_object'].encode('utf-8')))
    return dct

data = [1,2,3, set(['knights', 'who', 'say', 'ni']), {'key':'value'}, Decimal('3.14')]
j = dumps(data, cls=PythonObjectEncoder)
print(loads(j, object_hook=as_python_object))
# prints: [1, 2, 3, {'knights', 'who', 'say', 'ni'}, {'key': 'value'}, Decimal('3.14')]

퀵 덤프만 필요하고 커스텀 인코더를 실장하고 싶지 않은 경우.다음을 사용할 수 있습니다.

json_string = json.dumps(data, iterable_as_array=True)

이것에 의해, 모든 세트(및 그 외의 반복 가능)가 어레이로 변환됩니다.JSON을 다시 해석할 때 이러한 필드는 어레이 상태로 유지되도록 주의하십시오.유형을 보존하려면 커스텀인코더를 쓸 필요가 있습니다.

꼭 계셔야 합니다.simplejson설치 및 필수입니다.
PyPi에서 찾을 수 있습니다.

JSON에서는 사전, 목록 및 원시 개체 유형(int, string, bool)만 사용할 수 있습니다.

일반적인 Python 객체가 아닌 집합만 인코딩하고 쉽게 사람이 읽을 수 있도록 하려면 Raymond Hettinger의 답변을 단순화한 버전을 사용할 수 있습니다.

import json
import collections

class JSONSetEncoder(json.JSONEncoder):
    """Use with json.dumps to allow Python sets to be encoded to JSON

    Example
    -------

    import json

    data = dict(aset=set([1,2,3]))

    encoded = json.dumps(data, cls=JSONSetEncoder)
    decoded = json.loads(encoded, object_hook=json_as_python_set)
    assert data == decoded     # Should assert successfully

    Any object that is matched by isinstance(obj, collections.Set) will
    be encoded, but the decoded value will always be a normal Python set.

    """

    def default(self, obj):
        if isinstance(obj, collections.Set):
            return dict(_set_object=list(obj))
        else:
            return json.JSONEncoder.default(self, obj)

def json_as_python_set(dct):
    """Decode json {'_set_object': [1,2,3]} to set([1,2,3])

    Example
    -------
    decoded = json.loads(encoded, object_hook=json_as_python_set)

    Also see :class:`JSONSetEncoder`

    """
    if '_set_object' in dct:
        return set(dct['_set_object'])
    return dct

@AntiHaapala의 단축판:

json.dumps(dict_with_sets, default=lambda x: list(x) if isinstance(x, set) else x)
>>> import json
>>> set_object = set([1,2,3,4])
>>> json.dumps(list(set_object))
'[1, 2, 3, 4]'

승인된 솔루션의 단점 중 하나는 출력이 매우 비단뱀에 고유하다는 것입니다.즉, raw json 출력을 사람이 관찰하거나 다른 언어(예: javascript)로 로드할 수 없습니다.예:

db = {
        "a": [ 44, set((4,5,6)) ],
        "b": [ 55, set((4,3,2)) ]
        }

j = dumps(db, cls=PythonObjectEncoder)
print(j)

다음과 같은 이점을 얻을 수 있습니다.

{"a": [44, {"_python_object": "gANjYnVpbHRpbnMKc2V0CnEAXXEBKEsESwVLBmWFcQJScQMu"}], "b": [55, {"_python_object": "gANjYnVpbHRpbnMKc2V0CnEAXXEBKEsCSwNLBGWFcQJScQMu"}]}

동일한 인코더를 사용하여 python에 로드했을 때 목록을 포함하는 dict로 세트를 다운그레이드하고 이를 통해 관찰 가능성과 언어 불가지론을 유지하는 솔루션을 제안할 수 있습니다.

from decimal import Decimal
from base64 import b64encode, b64decode
from json import dumps, loads, JSONEncoder
import pickle

class PythonObjectEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (list, dict, str, int, float, bool, type(None))):
            return super().default(obj)
        elif isinstance(obj, set):
            return {"__set__": list(obj)}
        return {'_python_object': b64encode(pickle.dumps(obj)).decode('utf-8')}

def as_python_object(dct):
    if '__set__' in dct:
        return set(dct['__set__'])
    elif '_python_object' in dct:
        return pickle.loads(b64decode(dct['_python_object'].encode('utf-8')))
    return dct

db = {
        "a": [ 44, set((4,5,6)) ],
        "b": [ 55, set((4,3,2)) ]
        }

j = dumps(db, cls=PythonObjectEncoder)
print(j)
ob = loads(j)
print(ob["a"])

그 결과, 다음과 같습니다.

{"a": [44, {"__set__": [4, 5, 6]}], "b": [55, {"__set__": [2, 3, 4]}]}
[44, {'__set__': [4, 5, 6]}]

가 있는 요소가 있는 사전을 직렬화하는 데 유의하십시오."__set__"을 사용하다 ★★★★★★★★★★★★★★★★★.__set__ 유보적인 가 되었습니다.dict열쇠요. 분명히 더 깊게 난독화된 다른 키를 사용하셔도 됩니다.

jsonwhything을 시도해 보세요.

https://pypi.org/project/jsonwhatever/

pip install jsonwhaty

from jsonwhatever import JsonWhatEver

set_a = {1,2,3}

jsonwe = JsonWhatEver()

string_res = jsonwe.jsonwhatever('set_string', set_a)

print(string_res)

언급URL : https://stackoverflow.com/questions/8230315/how-to-json-serialize-sets