Why does json.dump not call __getstate__



我有一个python类,关于以下内容,重要的部分是ctypes库。

from ctypes import *
class PyClassExample:
def __init__(self):
self.path = '/some/unix/path/file.so'
self.lib = CDLL(self.path) # non-serializable element
self.arr = [1, 2, 3, 4] # serializable element
def __getstate__(self):
state = self.__dict__.copy()
del state['lib']

return state

当我尝试在它的实例化对象上调用json.dump时,我得到一个错误消息:

TypeError: PyClassExample类型的对象不是JSON可序列化的

为什么json.dump不调用__getstate__pickle.dump调用它?json.dump使用什么机制来获取传递对象的可序列化状态?

包含__getstate__的协议是为Pickle设计的,它被设计成能够序列化几乎任何Python对象。它是一种灵活的格式,可以存储对象类型及其状态。

JSON没有这个功能。它只支持一组固定的类型,扩展格式通常是通过在后处理步骤中解释值来完成的(比如在dict中读取预定义的键)。你可以这样做:

import json
def my_default(o):
if isinstance(o, PyClassExample):
return {'$type': 'PyClassExample', 'path': o.path, 'arr': o.arr}
raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
def my_object_hook(o):
if o.get('$type') == 'PyClassExample':
# FIXME: implement an __init__ that supports this
return PyClassExample(o)
return o

然后用json.dump(..., default=my_default)代替对json.dump(...)的调用,用json.load(..., object_hook=my_object_hook)代替对json.load(...)的调用。

如果你想支持更多的类,你可能想要一个更通用的解决方案,像一个协议"JSON-able"类。如果你真的想,你甚至可以滥用__getstate__,像这样:

import json
# Make all classes you want to be able to serialise that need to use this mechanism a subclass of JSONAble
class JSONAble:
registry = {}
def __init_subclass__(cls, /, **kwargs):
super().__init_subclass__(**kwargs)
JSONAble.registry[cls.__name__] = cls
def my_default(o):
if isinstance(o, JSONAble):
return {'(type)': type(o).__name__, **o.__getstate__()}
raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
def my_object_hook(o):
if '(type)' in o:
new_o = JSONAble.registry[o.pop('(type)')]()
new_o.__dict__ = o
return new_o
return o

最新更新