Python对象内numpy数组的JSON序列化与反序列化问题
我来帮你解决这个包含numpy数组的Student对象JSON序列化/反序列化问题。你遇到的问题本质是JSON原生仅支持字符串、数字、列表、字典等基础类型,numpy.ndarray属于自定义类型,jsonpickle默认处理逻辑没做专门适配,导致序列化后numpy相关信息丢失或结构异常。下面给你两种靠谱的解决方案:
方案一:自定义JSON编码器和解码器
这种方法不依赖第三方库(只用Python标准库的json模块),通过自定义编码/解码逻辑,手动处理numpy数组的转换:
首先修正你的Student类,把ndarr的类型从字符串改为numpy数组(原来的字符串定义是错误的):
import json import numpy as np class Student(object): def __init__(self, name, age, major): self.name = name self.age = age self.major = major self.ndarr = None # 初始化设为None,后续赋值为numpy数组
然后编写自定义编码器,遇到numpy数组时将其转为包含数据列表和 dtype 的字典:
class NumpyJSONEncoder(json.JSONEncoder): def default(self, obj): # 处理numpy数组 if isinstance(obj, np.ndarray): return { "__ndarray__": obj.tolist(), "dtype": str(obj.dtype) } # 处理Student对象,直接返回其属性字典 elif isinstance(obj, Student): return obj.__dict__ # 其他类型交给默认逻辑处理 return super().default(obj)
再编写自定义解码器,识别标记__ndarray__并还原为numpy数组,同时还原Student对象:
def numpy_json_decoder(obj): # 还原numpy数组 if "__ndarray__" in obj: return np.array(obj["__ndarray__"], dtype=obj["dtype"]) # 还原Student对象 if all(key in obj for key in ["name", "age", "major", "ndarr"]): student = Student(obj["name"], obj["age"], obj["major"]) student.ndarr = numpy_json_decoder(obj["ndarr"]) return student # 其他类型直接返回 return obj
使用示例:
# 创建带numpy数组的Student实例 student = Student("Alice", 22, "Computer Science") student.ndarr = np.array([[1,2,3], [4,5,6]], dtype=np.float64) # 序列化 json_str = json.dumps(student, cls=NumpyJSONEncoder, indent=2) print("Serialized JSON:\n", json_str) # 反序列化 loaded_student = json.loads(json_str, object_hook=numpy_json_decoder) print("\nDeserialized Student:") print(f"Name: {loaded_student.name}, Age: {loaded_student.age}") print(f"ndarr type: {type(loaded_student.ndarr)}") # 输出 <class 'numpy.ndarray'> print(f"ndarr content:\n{loaded_student.ndarr}")
方案二:给jsonpickle添加自定义处理器
如果你想继续使用jsonpickle,可以给它注册专门处理numpy数组的编码器和解码器,让它知道如何正确序列化/反序列化ndarray:
import jsonpickle import numpy as np # 保持修正后的Student类(同方案一) class Student(object): def __init__(self, name, age, major): self.name = name self.age = age self.major = major self.ndarr = None # 定义numpy数组的编码函数 def ndarr_encode(obj): return { "__ndarray__": obj.tolist(), "dtype": str(obj.dtype) } # 定义numpy数组的解码函数 def ndarr_decode(obj): if "__ndarray__" in obj: return np.array(obj["__ndarray__"], dtype=obj["dtype"]) return obj # 注册处理器到jsonpickle jsonpickle.handlers.register(np.ndarray, ndarr_encode, ndarr_decode) # 使用示例 student = Student("Bob", 21, "Mathematics") student.ndarr = np.array([10,20,30], dtype=np.int32) # 序列化 frozen = jsonpickle.encode(student, indent=2) print("jsonpickle serialized object:\n", frozen) # 反序列化 unfrozen = jsonpickle.decode(frozen) print("\nDeserialized Student:") print(f"Name: {unfrozen.name}, Age: {unfrozen.age}") print(f"ndarr type: {type(unfrozen.ndarr)}") # 输出 <class 'numpy.ndarray'> print(f"ndarr content: {unfrozen.ndarr}")
两种方案的核心思路都是:把numpy数组转成JSON可识别的基础类型组合(字典+列表),反序列化时再根据标记还原成原类型,这样就能保证numpy数组的结构和 dtype 信息不丢失。
内容的提问来源于stack exchange,提问作者mjpablo23
相关产品推荐
相关产品推荐

