나는 파이썬이 set
가진 개체를 포함 __hash__
하고 __eq__
특정없고 중복을하기 위해 방법이 컬렉션에 포함되어 있습니다.
이 결과를 json으로 인코딩해야 set
하지만 비어 set
있는 json.dumps
메소드를 메소드에 전달 하면 a가 발생합니다 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
할 수있는 반면 다른 객체에는 “기본이 아닌”객체를 포함하는 키가없는 다른 스키마가있을 수 있습니다.
그렇기 때문에 내가 생각할 수있는 유일한 솔루션 은 다른 경우를 켜기 JSONEncoder
위해 default
방법을 대체 하기 위해 확장하는 것이 었습니다 . 중첩 된 객체에서 default
go by key 에서 반환 된 값 이 전체 객체를 보는 일반적인 포함 / 삭제입니까? 이 방법은 중첩 값을 어떻게 수용합니까? 이전 질문을 살펴본 결과 사례 별 인코딩에 대한 최선의 접근 방법을 찾지 못하는 것 같습니다 (불행히도 여기서해야 할 일처럼 보입니다).
답변
JSON 표기법에는 소수의 기본 데이터 유형 (객체, 배열, 문자열, 숫자, 부울 및 null) 만 있으므로 JSON으로 직렬화 된 항목은 이러한 유형 중 하나로 표현해야합니다.
json 모듈 docs에 표시된 것처럼 이 변환은 JSONEncoder 및 JSONDecoder에 의해 자동으로 수행 될 수 있지만 필요한 다른 구조를 포기하게됩니다 (세트로 목록을 변환하면 정기적으로 복구 할 수있는 기능이 손실 됨) 목록을 사용하여 세트를 사전으로 변환하면 사전 dict.fromkeys(s)
을 복구하는 기능이 손실됩니다).
보다 정교한 솔루션은 다른 기본 JSON 유형과 공존 할 수있는 사용자 정의 유형을 빌드하는 것입니다. 이를 통해 목록, 집합, dicts, 소수, 날짜 시간 객체 등을 포함하는 중첩 구조를 저장할 수 있습니다.
from json import dumps, loads, JSONEncoder, JSONDecoder
import pickle
class PythonObjectEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, (list, dict, str, unicode, int, float, bool, type(None))):
return JSONEncoder.default(self, obj)
return {'_python_object': pickle.dumps(obj)}
def as_python_object(dct):
if '_python_object' in dct:
return pickle.loads(str(dct['_python_object']))
return dct
다음은 목록, dicts 및 세트를 처리 할 수 있음을 보여주는 샘플 세션입니다.
>>> 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']), {u'key': u'value'}, Decimal('3.14')]
또는 YAML , Twisted Jelly 또는 Python의 pickle 모듈 과 같은보다 일반적인 용도의 직렬화 기술을 사용하는 것이 유용 할 수 있습니다 . 이들은 각각 훨씬 더 넓은 범위의 데이터 유형을 지원합니다.
답변
당신은을 반환하는 사용자 지정 인코더 만들 수 있습니다 list
그것이 발생 때를 set
. 예를 들면 다음과 같습니다.
>>> import json
>>> class SetEncoder(json.JSONEncoder):
... def default(self, obj):
... if isinstance(obj, set):
... return list(obj)
... return json.JSONEncoder.default(self, obj)
...
>>> json.dumps(set([1,2,3,4,5]), cls=SetEncoder)
'[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
반환 된 결과 를 가져 와서 자식의 serializer를 재귀 적으로 호출 함을 나타냅니다 . 여러 유형에 대한 사용자 정의 직렬 변환기를 추가하려면 다음을 수행하십시오.
>>> 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)
...
>>> json.dumps(set([1,2,3,4,5,Something()]), cls=SetEncoder)
'[1, 2, 3, 4, 5, "CustomSomethingRepresentation"]'
답변
나는 적응 레이몬드 Hettinger의 솔루션 파이썬 3를.
변경된 내용은 다음과 같습니다.
unicode
사라졌다- 부모의 호출 업데이트
default
와super()
- 파이썬 3에서는 JSON으로 변환 할 수 없기 때문에 유형
base64
을 직렬화하는 데 사용bytes
str
bytes
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에서는 사전, 목록 및 기본 객체 유형 (int, string, bool) 만 사용할 수 있습니다.
답변
default
메소드 를 제공하기 위해 사용자 정의 인코더 클래스를 작성할 필요가 없습니다 . 키워드 인수로 전달 될 수 있습니다.
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 객체가 아닌 세트 만 인코딩하고 사람이 쉽게 읽을 수 있도록하려면 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
답변
빠른 덤프 만 필요하고 사용자 지정 인코더를 구현하지 않으려는 경우 다음을 사용할 수 있습니다.
json_string = json.dumps(data, iterable_as_array=True)
그러면 모든 세트 (및 기타 반복 가능 항목)가 배열로 변환됩니다. json을 구문 분석 할 때 해당 필드가 배열을 유지한다는 점에 유의하십시오. 유형을 유지하려면 사용자 정의 인코더를 작성해야합니다.