You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:52:07