직렬화할 수 없는 사용자 정의 객체를 JSON으로 직렬화하는 기본 방법은 json.JSONEncoder를 하위 클래스로 분류하고 사용자 정의 인코더를 전달하는 것입니다. json.dumps(). 이는 일반적으로 다음과 같습니다.
<code class="python">class CustomEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Foo): return obj.to_json() return json.JSONEncoder.default(self, obj) print(json.dumps(obj, cls=CustomEncoder))</code>
그러나 기본 인코더를 사용하여 객체를 직렬화할 수 있도록 하려면 어떻게 해야 할까요? json 모듈의 소스 코드를 검토한 결과 인코더를 직접 확장하는 것은 이 요구 사항을 충족하지 못하는 것으로 보입니다.
대신 패키지의 __init__.py 초기화 스크립트 내에서 "monkey-patching"이라는 기술을 사용할 수 있습니다. 모듈은 일반적으로 한 번만 로드되고 결과는 sys.modules에 캐시되므로 이는 모든 후속 JSON 모듈 직렬화에 영향을 미칩니다.
패치는 고유한 "to_json" 메서드를 확인하기 위해 기본 JSON 인코더의 기본 메서드를 수정합니다. 발견된 경우 이를 활용하여 개체를 인코딩합니다.
다음은 단순성을 위해 독립형 모듈로 구현된 예입니다.
<code class="python"># Module: make_json_serializable.py from json import JSONEncoder def _default(self, obj): return getattr(obj.__class__, "to_json", _default.default)(obj) _default.default = JSONEncoder.default # Save unmodified default. JSONEncoder.default = _default # Replace it.</code>
이 패치를 사용하는 것은 간단합니다. 모듈을 가져와서 원숭이를 적용하면 됩니다. -patch.
<code class="python"># Sample client script import json import make_json_serializable # apply monkey-patch class Foo(object): def __init__(self, name): self.name = name def to_json(self): # New special method. """Convert to JSON format string representation.""" return '{"name": "%s"}' % self.name foo = Foo('sazpaz') print(json.dumps(foo)) # -> '{"name": "sazpaz"}'</code>
객체 유형 정보를 유지하기 위해 to_json 메서드는 반환된 문자열에 해당 정보를 포함할 수 있습니다.
<code class="python">def to_json(self): """Convert to JSON format string representation.""" return '{"type": "%s", "name": "%s"}' % (self.__class__.__name__, self.name)</code>
이렇게 하면 클래스 이름이 포함된 JSON이 생성됩니다.
{"type": "Foo", "name": "sazpaz"}
더욱 강력한 접근 방식은 대체 기본 메서드를 사용하여 고유한 메서드 없이 사용자 정의 클래스 인스턴스를 포함한 대부분의 Python 객체를 자동으로 직렬화하는 것입니다.
여러 대안을 조사한 결과 피클을 기반으로 한 다음 접근 방식이 이 이상에 가장 가까운 것으로 나타났습니다.
<code class="python"># Module: make_json_serializable2.py from json import JSONEncoder import pickle def _default(self, obj): return {"_python_object": pickle.dumps(obj)} JSONEncoder.default = _default # Replace with the above.</code>
모든 것을 피클할 수는 없지만(예: 확장 유형) 피클은 프로토콜을 통해 이를 처리하는 방법을 제공합니다. 독특한 방법을 사용합니다. 그러나 이 접근 방식은 더 많은 경우를 포괄합니다.
피클 프로토콜을 사용하면 "_python_object"가 발생할 때 json.loads()에 사용자 정의 object_hook 함수 인수를 제공하여 원래 Python 객체를 재구성하는 것이 단순화됩니다. 키를 사전에 넣습니다.
<code class="python">def as_python_object(dct): try: return pickle.loads(str(dct['_python_object'])) except KeyError: return dct pyobj = json.loads(json_str, object_hook=as_python_object)</code>
이것은 래퍼 함수로 단순화될 수 있습니다.
<code class="python">json_pkloads = functools.partial(json.loads, object_hook=as_python_object) pyobj = json_pkloads(json_str)</code>
json.dumps()가 바이트 객체를 반환하기 때문에 이 코드는 Python 3에서 작동하지 않습니다. JSONEncoder가 처리할 수 없는 문제입니다. 그러나 다음 수정을 통해 접근 방식은 여전히 유효합니다.
<code class="python">def _default(self, obj): return {"_python_object": pickle.dumps(obj).decode('latin1')} def as_python_object(dct): try: return pickle.loads(dct['_python_object'].encode('latin1')) except KeyError: return dct</code>
위 내용은 `json.JSONEncoder`를 서브클래싱하지 않고 사용자 정의 개체 JSON을 직렬화할 수 있도록 하려면 어떻게 해야 합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!