python3运行报错:TypeError: Object of type 'type' is not JSON serializable解决方法

本文介绍了解决Python中json.dumps遇到bytes类型数据时的编码问题。通过自定义编码类MyEncoder,可以将bytes类型转换为str类型,从而避免编码错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

报这个错的原因是因为json.dumps函数发现字典里面有bytes类型的数据,无法编码。解决方法:在编码函数之前写一个编码类,只要检查到了是bytes类型的数据就把它转化成str类型。

这个编码类代码示例如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json


class MyEncoder(json.JSONEncoder):

    def default(self, obj):
        """
        只要检查到了是bytes类型的数据就把它转为str类型
        :param obj:
        :return:
        """
        if isinstance(obj, bytes):
            return str(obj, encoding='utf-8')
        return json.JSONEncoder.default(self, obj)

 

<think>我们遇到了一个特定的问题:尝试将`float32`类型的数据写入JSON时出现`TypeError:Objectoftype&#39;float32&#39;isnotJSONserializable`错误。根据引用[1][2][4][5],这个错误的原因是标准JSON库只支持基本的数据类型(如Python内置的`float`,对应JSON中的数字类型),而`float32`是NumPy库中的数据类型,不是Python内置类型。目标:在不将数值转换为字符串的情况下,将`float32`类型的数据正确地写入JSON文件(保持为JSON数字类型)。解决方案:我们需要在序列化之前将`float32`转换为Python内置的`float`类型,或者使用自定义的JSON编码器来处理NumPy数据类型。以下是两种主要方法:###方法1:显式转换为Python内置的float类型在将数据传递给`json.dump`或`json.dumps`之前,将所有的`float32`值转换为Python的`float`类型。因为Python的`float`类型(实际上是双精度浮点数)是JSON标准支持的。示例代码:```pythonimportjsonimportnumpyasnp#假设我们有一个包含float32的数据结构data={"value":np.float32(3.14)}#在序列化之前转换float32为Pythonfloatdata_serializable={"value":float(data["value"])}#现在可以正常序列化json_str=json.dumps(data_serializable)print(json_str)#输出:{"value":3.14}```如果数据结构复杂(例如嵌套的字典或列表),我们可以编写一个递归转换函数:```pythonimportnumpyasnpdefconvert_floats(obj):ifisinstance(obj,np.floating):returnfloat(obj)elifisinstance(obj,np.integer):returnint(obj)elifisinstance(obj,list):return[convert_floats(item)foriteminobj]elifisinstance(obj,dict):return{key:convert_floats(value)forkey,valueinobj.items()}else:returnobj#使用示例data={"array":[np.float32(1.1),np.float32(2.2)],"nested":{"value":np.float32(3.3)}}converted_data=convert_floats(data)json_str=json.dumps(converted_data)print(json_str)#输出:{"array":[1.1,2.2],"nested":{"value":3.3}}```###方法2:自定义JSON编码器创建一个继承自`json.JSONEncoder`的类,并重写`default`方法,在该方法中处理NumPy的数据类型。示例代码:```pythonimportjsonimportnumpyasnpclassNumpyEncoder(json.JSONEncoder):defdefault(self,obj):ifisinstance(obj,np.floating):returnfloat(obj)elifisinstance(obj,np.integer):returnint(obj)elifisinstance(obj,np.ndarray):returnobj.tolist()else:returnsuper().default(obj)#使用自定义编码器data={"value":np.float32(3.14),"array":np.array([1.0,2.0],dtype=np.float32)}json_str=json.dumps(data,cls=NumpyEncoder)print(json_str)#输出:{"value":3.14,"array":[1.0,2.0]}```这样,在调用`json.dump`或`json.dumps`时,只需指定`cls=NumpyEncoder`参数即可。###两种方法比较-**方法1**适用于数据结构简单或只需一次性转换的情况。-**方法2**更为通用,尤其当我们在多个地方需要序列化包含NumPy类型的数据时,可以复用编码器。###写入JSONL文件如果我们有大量数据需要写入JSONL文件(每行一个JSON对象),可以结合方法2:```pythonimportjsonimportnumpyasnpclassNumpyEncoder(json.JSONEncoder):defdefault(self,obj):#处理NumPy数据类型ifisinstance(obj,np.floating):returnfloat(obj)elifisinstance(obj,np.integer):returnint(obj)elifisinstance(obj,np.ndarray):returnobj.tolist()else:returnsuper().default(obj)#生成350行数据,每行是一个字典,其中包含float32类型的值data_list=[{"PredictResult":np.float32(1.0)}for_inrange(350)]withopen(&#39;result.jsonl&#39;,&#39;w&#39;)asf:fordataindata_list:#使用自定义编码器将每个对象转换为JSON字符串并写入文件json_line=json.dumps(data,cls=NumpyEncoder)f.write(json_line+&#39;\n&#39;)```这样,每行写入的JSON对象中的`PredictResult`值都是数字类型(如`1.0`),而不是字符串。###注意事项1.**精度问题**:将`float32`转换为Python的`float`(即`float64`)可能会增加一些内存开销,但不会损失精度,因为`float32`可以精确表示为`float64`[^4]。2.**特殊值**:如果数据中包含`NaN`或`Infinity`,需要确保JSON编码器允许这些值(标准JSON不支持,但可以通过设置`allow_nan=True`,并且自定义编码器需要处理这些情况)。###总结通过将NumPy的`float32`类型转换为Python内置的`float`类型,我们可以避免`TypeError`错误,同时保持JSON中的数值类型(非字符串)。推荐使用自定义JSON编码器,这样代码更清晰且可复用。###相关问题1.如何处理JSON序列化中的NumPy数组?2.自定义JSON编码器还能处理哪些非标准类型?3.在大型科学计算中,如何高效地将包含NumPy类型的数据保存为JSON格式?4.除了JSON,还有哪些更适合存储数值数据的序列化格式(如HDF5)?</think>### 解决 float32 类型无法 JSON 序列化的完整方案 #### 问题原因分析 当尝试序列化 NumPy 的 `float32` 类型时,Python 标准库的 `json` 模块无法识别这种类型,因为 JSON 标准仅支持基础数据类型(如 Python 内置的 `float` 类型)。引用[4]明确指出:"JSON标准只支持一些基本的数据类型,如字符串、数字(通常是int或float)、布尔值、列表、字典等"[^4]。 --- ### 解决方案(保持数值类型,不转为字符串) #### 方法1:转换为 Python 内置 float 类型(推荐) 最直接高效的方法是将 `float32` 转换为 Python 内置的 `float` 类型: ```python import numpy as np import json # 原始 float32 数据 np_float = np.float32(3.14) # 转换为 Python 内置 float py_float = float(np_float) # 成功序列化(保持数值类型) json.dumps({"value": py_float}) # 输出: {"value": 3.14} ``` #### 方法2:自定义 JSON 编码器(处理复杂结构) 当数据结构复杂(包含嵌套字典/列表)时,使用自定义编码器: ```python import json import numpy as np from json import JSONEncoder class NumpyEncoder(JSONEncoder): def default(self, obj): # 处理 float32 和 float64 if isinstance(obj, np.floating): return float(obj) # 关键转换:np.float -> Python float # 处理其他 NumPy 类型(可选) if isinstance(obj, np.integer): return int(obj) if isinstance(obj, np.ndarray): return obj.tolist() return super().default(obj) # 使用示例 data = { "sensor_data": np.float32(98.6), "matrix": np.array([[1.2, 3.4], [5.6, 7.8]], dtype=np.float32) } # 序列化时指定编码器 json_str = json.dumps(data, cls=NumpyEncoder) # 结果: {"sensor_data": 98.6, "matrix": [[1.2, 3.4], [5.6, 7.8]]} ``` #### 方法3:数据预处理(批量转换) 对于大型数据集,使用递归转换: ```python import numpy as np def convert_numpy(obj): if isinstance(obj, np.floating): return float(obj) if isinstance(obj, np.integer): return int(obj) if isinstance(obj, dict): return {k: convert_numpy(v) for k, v in obj.items()} if isinstance(obj, list): return [convert_numpy(item) for item in obj] return obj # 使用示例 raw_data = {"temp": np.float32(36.5), "readings": [np.float32(1.1), np.float32(2.2)]} converted_data = convert_numpy(raw_data) json.dumps(converted_data) # 成功序列化 ``` --- ### 写入 JSONL 文件的完整示例 ```python import json import numpy as np from tqdm import tqdm # 进度条库(可选) class NumpyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, np.floating): return float(obj) return super().default(obj) # 生成 350 行包含 float32 的数据 data_generator = ({"id": i, "value": np.float32(i * 0.1)} for i in range(350)) with open(&#39;data.jsonl&#39;, &#39;w&#39;) as f: for record in tqdm(data_generator, total=350, desc="写入进度"): json_line = json.dumps(record, cls=NumpyEncoder) f.write(json_line + &#39;\n&#39;) ``` #### 文件内容示例 ```json {"id": 0, "value": 0.0} {"id": 1, "value": 0.1} {"id": 2, "value": 0.2} ... ``` --- ### 关键原理 1. **类型转换的本质** 所有方法的核心都是将 `np.float32` 转换为 JSON 可识别的 Python `float` 类型: $$ \text{np.float32} \xrightarrow{\text{float()}} \text{Python float} \xrightarrow{\text{json.dumps}} \text{JSON number} $$ 2. **避免的常见错误** ```python # 错误方法1:直接序列化(引发 TypeErrorjson.dumps(np.float32(1.0)) # 错误方法2:转为字符串(不符合要求) json.dumps(str(np.float32(1.0))) # 结果带引号:"1.0" ``` 3. **精度处理** 转换过程中数值精度保持不变,因为 Python `float` (float64) 完全覆盖 `float32` 的精度范围[^4]。 --- ### 相关问题 1. 如何同时处理 JSON 序列化中的多种 NumPy 数据类型(int32, float64 等)? 2. 自定义 JSON 编码器能否处理 Pandas DataFrame 中的混合数据类型? 3. 在科学计算中,除了 JSON 还有哪些更高效的数值数据存储格式? 4. 如何优化千万级浮点数数据的 JSON 序列化性能? > 解决方案均通过保持数值类型(非字符串)实现,符合 JSON 标准中的数字类型规范[^2][^4]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值