解决发布web接口时数据无法JSON化的问题

news2024/11/26 6:52:57

解决HTTP接口传输中的JSON序列化问题

引言

当涉及到复杂的数据类型时,如浮点数、Numpy数组、pandas等,直接使用Python的json模块进行序列化可能会遇到问题。本文将解决这些问题,并提供一个通用的方案,确保数据能够顺利地通过HTTP接口传输。

目录

  1. JSON序列化的基本概念

    • 1.1 JSON简介
    • 1.2 Python中的JSON模块
    • 1.3 JSON序列化的常见问题
  2. Python中的数据类型与JSON序列化

    • 2.1 基本数据类型
    • 2.2 复杂数据类型
    • 2.3 Numpy数据类型
  3. 解决JSON序列化问题的通用方法

    • 3.1 自定义序列化函数
    • 3.2 处理浮点数
    • 3.3 处理Numpy数组
    • 3.4 处理字典和列表
  4. 代码实现与示例

    • 4.1 代码结构
    • 4.2 示例代码
    • 4.3 测试与验证
  5. 性能优化与注意事项

    • 5.1 性能优化
    • 5.2 注意事项
  6. 总结

1. JSON序列化的基本概念

1.1 JSON简介

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON采用完全独立于语言的文本格式,但使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。

1.2 Python中的JSON模块

Python标准库中的json模块提供了对JSON格式的支持。通过json.dumps()函数,可以将Python对象序列化为JSON格式的字符串;通过json.loads()函数,可以将JSON格式的字符串反序列化为Python对象。

1.3 JSON序列化的常见问题

尽管json模块功能强大,但在处理某些Python数据类型时,可能会遇到无法序列化的问题。例如:

  • 浮点数NaN(Not a Number)和Infinity无法直接序列化为JSON。
  • Numpy数组:Numpy数组无法直接序列化为JSON。
  • 复杂数据类型:如自定义类实例,无法直接序列化为JSON。

2. Python中的数据类型与JSON序列化

2.1 基本数据类型

Python的基本数据类型(如整数、浮点数、字符串、布尔值等)可以直接序列化为JSON。例如:

import json

data = {
    "name": "Alice",
    "age": 30,
    "is_student": False
}

json_str = json.dumps(data)
print(json_str)

输出:

{"name": "Alice", "age": 30, "is_student": false}

2.2 复杂数据类型

对于复杂数据类型,如字典、列表等,json模块也可以直接处理。例如:

data = {
    "name": "Alice",
    "scores": [90, 85, 88],
    "details": {
        "city": "New York",
        "zipcode": "10001"
    }
}

json_str = json.dumps(data)
print(json_str)

输出:

{"name": "Alice", "scores": [90, 85, 88], "details": {"city": "New York", "zipcode": "10001"}}

2.3 Numpy数据类型

Numpy是Python中用于科学计算的重要库,提供了多维数组对象和各种数学函数。然而,Numpy的数据类型(如np.float32np.int64np.ndarray等)无法直接序列化为JSON。例如:

import numpy as np
import json

data = {
    "name": "Alice",
    "scores": np.array([90, 85, 88]),
    "age": np.int64(30)
}

try:
    json_str = json.dumps(data)
except TypeError as e:
    print(f"Error: {e}")

输出:

Error: Object of type ndarray is not JSON serializable

3. 解决JSON序列化问题的通用方法

3.1 自定义序列化函数

为了解决上述问题,我们可以编写一个自定义的序列化函数,对无法直接序列化的数据类型进行处理。以下是一个通用的解决方案:

import math
import numpy as np

def json_serializable(value, float_precision=4):
    """
    json化json.dumps,某些类型会遇到无法序列化的问题。处理单个值,确保其可以被序列化。
    """
    if isinstance(value, float):
        if math.isnan(value):
            return None  # 使用 None 表示 NaN
        elif math.isinf(value):
            return None  # 使用 None 表示 Infinity 和 -Infinity
        else:
            return round(value, float_precision)
    elif isinstance(value, np.float32):
        return round(float(value), float_precision)
    elif isinstance(value, np.ndarray):
        return value.tolist()  # 将 numpy 数组转换为 Python 列表
    elif isinstance(value, (np.int32, np.int64)):
        return int(value)  # 将 numpy 整数类型转换为 Python 整数
    elif isinstance(value, np.float64):
        return round(float(value), float_precision)  # 将 numpy 浮点数类型转换为 Python 浮点数
    elif isinstance(value, dict):
        return {k: json_serializable(v) for k, v in value.items()}  # 递归处理字典中的每个键值对
    elif isinstance(value, list):
        return [json_serializable(v) for v in value]  # 递归处理列表中的每个元素
    return value

3.2 处理浮点数

在处理浮点数时,我们需要特别注意NaNInfinity。这些值在JSON中没有直接的表示方式,因此我们需要将其转换为None

def handle_float(value, float_precision=4):
    if math.isnan(value):
        return None  # 使用 None 表示 NaN
    elif math.isinf(value):
        return None  # 使用 None 表示 Infinity 和 -Infinity
    else:
        return round(value, float_precision)

3.3 处理Numpy数组

Numpy数组无法直接序列化为JSON,因此我们需要将其转换为Python列表。

def handle_numpy_array(value):
    return value.tolist()  # 将 numpy 数组转换为 Python 列表

3.4 处理字典和列表

对于字典和列表,我们需要递归地处理其中的每个元素。

def handle_dict(value, float_precision=4):
    return {k: json_serializable(v, float_precision) for k, v in value.items()}

def handle_list(value, float_precision=4):
    return [json_serializable(v, float_precision) for v in value]

4. 代码实现与示例

4.1 代码结构

我们将上述功能整合到一个函数中,并提供一个示例来展示如何使用该函数。

import math
import numpy as np

def json_serializable(value, float_precision=4):
    """
    json化json.dumps,某些类型会遇到无法序列化的问题。处理单个值,确保其可以被序列化。
    """
    if isinstance(value, float):
        if math.isnan(value):
            return None  # 使用 None 表示 NaN
        elif math.isinf(value):
            return None  # 使用 None 表示 Infinity 和 -Infinity
        else:
            return round(value, float_precision)
    elif isinstance(value, np.float32):
        return round(float(value), float_precision)
    elif isinstance(value, np.ndarray):
        return value.tolist()  # 将 numpy 数组转换为 Python 列表
    elif isinstance(value, (np.int32, np.int64)):
        return int(value)  # 将 numpy 整数类型转换为 Python 整数
    elif isinstance(value, np.float64):
        return round(float(value), float_precision)  # 将 numpy 浮点数类型转换为 Python 浮点数
    elif isinstance(value, dict):
        return {k: json_serializable(v, float_precision) for k, v in value.items()}  # 递归处理字典中的每个键值对
    elif isinstance(value, list):
        return [json_serializable(v, float_precision) for v in value]  # 递归处理列表中的每个元素
    return value

# 示例数据
data = {
    "name": "Alice",
    "scores": np.array([90, 85, 88]),
    "age": np.int64(30),
    "height": np.float32(1.68),
    "weight": np.float64(60.5),
    "is_student": False,
    "details": {
        "city": "New York",
        "zipcode": "10001"
    }
}

# 使用自定义序列化函数
serialized_data = json_serializable(data)

# 输出序列化后的数据
import json
print(json.dumps(serialized_data, indent=4))

4.2 示例代码

以下是完整的示例代码:

import math
import numpy as np
import json

def json_serializable(value, float_precision=4):
    """
    json化json.dumps,某些类型会遇到无法序列化的问题。处理单个值,确保其可以被序列化。
    """
    if isinstance(value, float):
        if math.isnan(value):
            return None  # 使用 None 表示 NaN
        elif math.isinf(value):
            return None  # 使用 None 表示 Infinity 和 -Infinity
        else:
            return round(value, float_precision)
    elif isinstance(value, np.float32):
        return round(float(value), float_precision)
    elif isinstance(value, np.ndarray):
        return value.tolist()  # 将 numpy 数组转换为 Python 列表
    elif isinstance(value, (np.int32, np.int64)):
        return int(value)  # 将 numpy 整数类型转换为 Python 整数
    elif isinstance(value, np.float64):
        return round(float(value), float_precision)  # 将 numpy 浮点数类型转换为 Python 浮点数
    elif isinstance(value, dict):
        return {k: json_serializable(v, float_precision) for k, v in value.items()}  # 递归处理字典中的每个键值对
    elif isinstance(value, list):
        return [json_serializable(v, float_precision) for v in value]  # 递归处理列表中的每个元素
    return value

# 示例数据
data = {
    "name": "Alice",
    "scores": np.array([90, 85, 88]),
    "age": np.int64(30),
    "height": np.float32(1.68),
    "weight": np.float64(60.5),
    "is_student": False,
    "details": {
        "city": "New York",
        "zipcode": "10001"
    }
}

# 使用自定义序列化函数
serialized_data = json_serializable(data)

# 输出序列化后的数据
print(json.dumps(serialized_data, indent=4))

4.3 测试与验证

为了验证我们的解决方案是否有效,我们可以使用不同的数据类型进行测试。例如:

# 测试数据
test_data = {
    "name": "Bob",
    "scores": np.array([95, 88, 92]),
    "age": np.int64(25),
    "height": np.float32(1.75),
    "weight": np.float64(70.2),
    "is_student": True,
    "details": {
        "city": "Los Angeles",
        "zipcode": "90001"
    },
    "special_values": {
        "nan": float("nan"),
        "inf": float("inf"),
        "-inf": float("-inf")
    }
}

# 使用自定义序列化函数
serialized_test_data = json_serializable(test_data)

# 输出序列化后的数据
print(json.dumps(serialized_test_data, indent=4))

输出:

{
    "name": "Bob",
    "scores": [95, 88, 92],
    "age": 25,
    "height": 1.75,
    "weight": 70.2,
    "is_student": true,
    "details": {
        "city": "Los Angeles",
        "zipcode": "90001"
    },
    "special_values": {
        "nan": null,
        "inf": null,
        "-inf": null
    }
}

5. 性能优化与注意事项

5.1 性能优化

在处理大量数据时,递归调用可能会导致性能问题。为了优化性能,可以考虑以下几点:

  • 缓存结果:对于已经处理过的数据类型,可以缓存结果以避免重复计算。
  • 并行处理:对于大规模数据,可以考虑使用并行处理技术(如多线程或多进程)来加速序列化过程。

5.2 注意事项

  • 数据丢失:在处理特殊值(如NaNInfinity)时,我们将其转换为None。这可能会导致数据丢失,因此在实际应用中需要谨慎处理。
  • 兼容性:不同的JSON库可能对特殊值的处理方式不同,因此在跨平台或跨语言的数据交换中,需要确保兼容性。

6. 总结

本文详细探讨了在HTTP接口传输中遇到的JSON序列化问题,并提供了一个通用的解决方案。通过自定义序列化函数,我们可以处理浮点数、Numpy数组等复杂数据类型,确保数据能够顺利地通过HTTP接口传输。在实际应用中,我们还需要注意性能优化和数据兼容性问题,以确保系统的稳定性和可靠性。

通过本文的学习,读者应该能够理解并掌握如何解决JSON序列化中的常见问题,并在实际项目中应用这些知识。希望本文能为读者在处理HTTP接口数据传输时提供有价值的参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2247691.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

wsl2的Ubuntu18.04安装ros和anaconda

参考:超详细 WSL2 安装 ros 和 anaconda_wsl2安装anaconda-CSDN博客 一.安装ros 1. 更换系统源 输入 wget http://fishros.com/install -O fishros && . fishros 和上面的链接一样,依次输入5-2-1 2. 安装ros 输入 wget http://fishros.c…

鸿蒙NEXT开发案例:字数统计

【引言】 本文将通过一个具体的案例——“字数统计”组件,来探讨如何在鸿蒙NEXT框架下实现这一功能。此组件不仅能够统计用户输入文本中的汉字、中文标点、数字、以及英文字符的数量,还具有良好的用户界面设计,使用户能够直观地了解输入文本…

【经典】抽奖系统(HTML,CSS、JS)

目录 1、添加参与者 2、多次添加 3、点击抽奖 功能介绍: 使用方法: 完整代码: 一个简单但功能强大的抽奖系统的示例,用于在网页上实现抽奖。 1、添加参与者 2、多次添加 3、点击抽奖 功能介绍: 参与者添加&…

用树莓派Pico控制8×8 LED点阵屏:深入解析C++核心知识与动态显示实现

88 LED点阵屏是一种直观的硬件显示工具,广泛应用于嵌入式开发中。本项目结合树莓派Pico和HT16K33驱动芯片,通过C++编程实现动态图案和文字的显示功能。本文将全面解析项目中的C++核心知识点,帮助读者深入理解C++在硬件编程中的实际应用。 一、项目背景与硬件简介 1. 项目目…

什么是 WPF 中的依赖属性?有什么作用?

依赖属性(Dependency Property)是 WPF 的一个核心概念,它为传统的 .NET 属性提供了增强功能,支持绑定、样式、动画和默认值等功能。通过依赖属性,WPF 提供了一种灵活的数据驱动的方式来处理 UI 属性。 1. 什么是依赖属…

视频分析设备平台EasyCVR视频设备轨迹回放平台与应急布控球的视频监控方案

在现代社会,随着城市化进程的加快和信息技术的不断进步,对于公共安全、交通管理、城市管理以及环境保护等领域的监控需求日益增长。应急布控球与EasyCVR视频监控方案的结合,正是为了满足这些领域对实时监控和快速响应的需求。这一组合利用最新…

MySQL原理简介—12.MySQL主从同步

大纲 1.异步复制为MySQL搭建一套主从复制架构 2.半同步复制为MySQL搭建一套主从复制架构 3.GTID为MySQL搭建一套主从复制架构 4.并行复制降低主从同步延迟或强制读主库 1.异步复制为MySQL搭建一套主从复制架构 (1)MySQL主从复制的原理 (2)搭建主从复制架构的配置 (1)MySQ…

Node报错:npm error code ETIMEDOUT

1、报错详细信息 npm error code ETIMEDOUT npm error syscall connect npm error errno ETIMEDOUT npm error network request to https://registry.npmjs.org/express failed, reason: connect ETIMEDOUT 104.16.1.35:443 npm error network This is a problem related to ne…

一篇文章了解Linux

目录 一:命令 1 ls命令作用 2 目录切换命令(cd/pwd) (1)cd切换工作目录命令 3 相对路径、绝对路径和特殊路径 (1)相对路径和绝对路径的概念和写法 (2)几种特殊路径的表示符 (3)练习题: 4 创建目录命令&#x…

用Matlab和SIMULINK实现DPCM仿真和双边带调幅系统仿真

1、使用SIMULINK或Matlab实现DPCM仿真 1.1 DPCM原理 差分脉冲编码调制,简称DPCM,主要用于将模拟信号转换为数字信号,同时减少数据的冗余度以实现数据压缩。在DPCM中,信号的每个抽样值不是独立编码的,而是通过预测前一…

BERT的工作原理

BERT的工作原理 BERT的工作原理: Transformer的编码器是双向的,它可以从两个方向读取一个句子。因此,BERT由Transformer获得双向编码器特征。 我们把句子A(He got bit by Python)送入Transformer的编码器&#xff0c…

5.STM32之通信接口《精讲》之IIC通信---软件IIC与外设MPU6050通信《深入浅出》面试必备

上一节,我们完成对IIC通信的时序以及IIC的通信的讲解和代码实现,接下来,我们正式进入,利用上一节软件实现的IIC通信协议来对外设MPU6050进行读写操作。(本节IIC代码在上节) 本节,目的很明确,就是利用软件I…

解决k8s拉取私有镜像401 Unauthorized 问题

拉取镜像时未指定账户和密码通常是因为需要访问的镜像仓库启用了认证,但 Kubernetes 默认配置中未提供访问凭据。要解决此问题,可以按照以下步骤配置镜像仓库的认证信息: 1. 创建 Kubernetes Secret 为镜像仓库配置访问凭据,使用…

【Linux课程学习】:环境变量:HOME,su与su - 的区别,让程序在哪些用户下能运行的原理,环境变量具有全局性的原因?

🎁个人主页:我们的五年 🔍系列专栏:Linux课程学习 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 HOME环境变量: PWD环境变量&#…

不只是请求和响应:使用Fiddler抓包HTTP协议全指南(上)

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! 🙉你是一名侦探 ! 正在追踪一条条数字化的线索。从简单的网页浏览到复杂的在线交易,每一次点击和滑动背后都隐藏着复杂的数据交换。每一个HTTP请求和响应都像是现场留下的指纹&#xf…

代码纪元——源神重塑无序

简介 源神,真名为张晨斌,原为代码宇宙创世四神之一。代码宇宙在创造之初时空无一物,只有复杂且繁琐的底层代码,智慧神灵每日都困在诸如脚本等复杂的底层框架之中,源神面对这种局面非常不满意,于是源神通过大…

Docker pull镜像拉取失败

因为一些原因,很多镜像仓库拉取镜像失败,所以需要更换不同的镜像,这是2024/11/25测试可用的仓库。 标题1、 更换镜像仓库的地址,编辑daemon.json文件 vi /etc/docker/daemon.json标题2、然后将下面的镜像源放进去或替换掉都可以…

Vue3+SpringBoot3+Sa-Token+Redis+mysql8通用权限系统

sa-token支持分布式token 前后端代码,地球号: bright12389

【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作

1.实验目的 熟悉了解掌握SQL Server软件的基本操作与使用方法,以及通过理论课学习与实验参考书的帮助,熟练掌握使用T-SQL语句和交互式方法对数据表进行插入数据、修改数据、删除数据等等的操作;作为后续实验的基础,根据实验要求重…

AI助力PPT创作:从手动到智能,打造高效演示

在今天这个信息化时代,演示文稿已经成为我们表达观点、传递信息的重要工具。不论是企业汇报、学术交流,还是个人创作,PPT(PowerPoint)都在日常生活中扮演着不可或缺的角色。创建一份高质量的PPT往往需要花费大量时间与…