pin_drop当前位置:知识文库 ❯ 图文

Python json.loads详解 - JSON解码与自定义解析技巧

一、概述

json.loads()json 模块中将 JSON 格式字符串反序列化为 Python 对象的函数。函数名中的 "loads" 代表 "load string",即从字符串加载数据。loads() 是处理 API 响应、配置文件内容、网络数据等 JSON 文本的核心函数,支持自定义解码逻辑和对象钩子。


二、语法

代码示例

import json

obj = json.loads(s, *, cls=None, object_hook=None,
                  parse_float=None, parse_int=None,
                  parse_constant=None, object_pairs_hook=None, **kw)

三、参数说明

参数 类型 默认值 说明
s str/bytes 必填 要解码的JSON字符串
cls type None 自定义JSONDecoder子类
object_hook callable None 解码dict时的回调函数
object_pairs_hook callable None 解码dict时保留键值对顺序的回调
parse_float callable None 自定义浮点数解析(默认float)
parse_int callable None 自定义整数解析(默认int)
parse_constant callable None 自定义NaN/Infinity解析

四、返回值

返回与 JSON 对应的 Python 对象。JSON object 映射为 dict,array 映射为 list,string 映射为 str,number 映射为 intfloat,true/false/null 映射为 True/False/None


五、代码示例

示例1:基本解码

代码示例

import json

# 解码各种JSON类型
json_strings = [
    '{"name": "张三", "age": 25}',
    '[1, 2, 3, "hello"]',
    '"Hello World"',
    '42',
    '3.14',
    'true',
    'null',
]

for s in json_strings:
    result = json.loads(s)
    print(f"  {s:40s} -> {result!r:30s} (类型: {type(result).__name__})")

输出:

代码示例

  {"name": "张三", "age": 25}                  -> {'name': '张三', 'age': 25}    (类型: dict)
  [1, 2, 3, "hello"]                        -> [1, 2, 3, 'hello']          (类型: list)
  "Hello World"                             -> 'Hello World'               (类型: str)
  42                                        -> 42                          (类型: int)
  3.14                                      -> 3.14                        (类型: float)
  true                                      -> True                        (类型: bool)
  null                                      -> None                        (类型: NoneType)

示例2:自定义解析函数

代码示例

import json
from decimal import Decimal

json_str = '{"price": 19.99, "count": 100, "ratio": 0.333}'

# 默认解析(float精度问题)
default_result = json.loads(json_str)
print(f"默认: price = {default_result['price']}")
print(f"  类型: {type(default_result['price']).__name__}")

# 使用Decimal解析浮点数
decimal_result = json.loads(json_str, parse_float=Decimal)
print(f"\nDecimal: price = {decimal_result['price']}")
print(f"  类型: {type(decimal_result['price']).__name__}")

# 自定义整数解析
str_int_result = json.loads(json_str, parse_int=str)
print(f"\n字符串整数: count = {str_int_result['count']!r}")
print(f"  类型: {type(str_int_result['count']).__name__}")

输出:

代码示例

默认: price = 19.99
  类型: float

Decimal: price = 19.99
  类型: Decimal

字符串整数: count = '100'
  类型: str

示例3:object_hook 自定义解码

代码示例

import json
from datetime import datetime

def datetime_hook(obj):
    """自动将ISO格式日期字符串转换为datetime对象"""
    for key, value in obj.items():
        if isinstance(value, str):
            try:
                obj[key] = datetime.fromisoformat(value)
            except ValueError:
                pass
    return obj

json_str = '''
{
    "name": "项目A",
    "created_at": "2024-01-15T14:30:00",
    "deadline": "2024-06-30",
    "status": "进行中"
}
'''

# 不使用hook
result_no_hook = json.loads(json_str)
print("不使用hook:")
print(f"  created_at类型: {type(result_no_hook['created_at']).__name__}")

# 使用hook
result_with_hook = json.loads(json_str, object_hook=datetime_hook)
print("\n使用hook:")
print(f"  created_at类型: {type(result_with_hook['created_at']).__name__}")
print(f"  created_at值: {result_with_hook['created_at']}")

输出:

代码示例

不使用hook:
  created_at类型: str

使用hook:
  created_at类型: datetime
  created_at值: 2024-01-15 14:30:00

六、实际应用场景

  • API 响应解析:将 HTTP 请求返回的 JSON 字符串解析为 Python 对象

  • 配置文件读取:读取 JSON 格式的配置文件内容

  • 数据类型精确控制:使用 parse_float 避免 float 精度问题,使用 object_hook 自动转换日期等类型


七、注意事项

注意1json.loads() 只接受有效的 JSON 字符串,无效格式会引发 json.JSONDecodeError(Python 3.5+),应做好异常处理。

注意2:JSON 数字中的浮点数在 Python 中默认解析为 float,存在精度问题。金融场景应使用 parse_float=Decimal

注意3object_hook 在每个 JSON object 解码完成后被调用,嵌套对象会从内到外依次触发。

提示:Python 3.6+ 的 json.loads() 也接受 bytesbytearray 类型作为输入,无需预先解码。


八、相关方法对比

特性 json.loads() json.load() ast.literal_eval() eval()
输入类型 str/bytes 文件对象 str str
安全性 安全 安全 安全 不安全
支持格式 JSON JSON Python字面量 任意Python
自定义解析 支持 支持 不支持 不适用
性能 较慢
推荐程度 推荐 推荐 可选 不推荐

九、小结

  • json.loads() 将 JSON 字符串反序列化为 Python 对象,是最常用的 JSON 解码函数

  • 支持自定义解析:parse_float(浮点精度)、parse_int(整数类型)、object_hook(对象转换)

  • 无效 JSON 会引发 JSONDecodeError,应做好异常捕获

  • 金融等精度敏感场景应使用 parse_float=Decimal 避免浮点精度损失


十、练习题

练习1

编写一个函数 safe_json_loads(s),捕获 JSONDecodeError 并返回 (result, error) 元组,成功时 error 为 None。

练习2

编写一个 object_hook 函数,自动将 JSON 中的下划线键名转换为驼峰命名(如 user_name -> userName)。

练习3

编写一个函数,使用 parse_float=Decimal 解析 JSON,验证浮点数精度在加减运算中的差异。

小贴士

object_hook 会在解码过程中对每一个 JSON 对象调用一次。如果你的 JSON 数据包含嵌套对象,object_hook 会从最内层的对象开始逐层向外调用。这意味着你可以利用这一特性,只转换特定层级的数据结构。另外,object_pairs_hook 接收有序键值对列表,适合需要保留原始键顺序的场景。

常见问题

json.loads() 可以解析 bytes 类型吗?

可以。Python 3.6+ 起,json.loads() 支持 str、bytes 和 bytearray 类型作为输入。对于 bytes 类型,会自动使用 UTF-8 解码,无需手动调用 decode()。

parse_float=Decimal 的性能影响大吗?

Decimal 的运算速度比 float 慢,但在金融和货币等精度敏感场景是值得的。如果数据量非常大且精度要求不高,建议保持默认的 float 解析以获得更好的性能。

object_hook 和 object_pairs_hook 有什么区别?

object_hook 接收已经转换为 dict 的对象,而 object_pairs_hook 接收有序键值对列表 [(key, value), ...]。如果同时设置了两个参数,object_pairs_hook 优先。使用 object_pairs_hook 可以保留 JSON 中的键值对原始顺序。

如何处理无效的 JSON 字符串?

使用 try-except 捕获 json.JSONDecodeError 异常。异常对象包含 msg(错误信息)、lineno(行号)和 colno(列号)属性,可以用于精确定位和报告错误位置。

标签: json.loads 反序列化 JSON解码 object_hook parse_float JSONDecodeError

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python json.dumps详解 - 序列化参数与格式化技巧 下一篇: Python json.dump详解 - 文件写入与流式序列化技巧

poll相关推荐