《Python 中 JSON 的魔法秘籍:从入门到精通的进阶指南》
在当今数字化时代,网络编程无处不在,数据的高效传输与交互是其核心。JSON 作为一种轻量级的数据交换格式,凭借其简洁、易读、跨语言的特性,成为网络编程中数据传输与存储的关键技术。无论是前后端数据交互,还是不同系统间的信息共享,JSON 都扮演着重要角色。Python 作为广泛应用于网络编程的编程语言,熟练掌握 JSON 在 Python 中的使用方法,是开发者实现高效数据处理与交互的必备技能,能够显著提升网络应用的性能和稳定性。
JSON简介
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,在 Python 中,json
模块提供了处理 JSON 数据的功能,使得 Python 程序可以方便地对数据进行序列化(将 Python 数据类型转换为 JSON 格式的字符串)和反序列化(将 JSON 格式的字符串转换回 Python 数据类型)。以下是 JSON 在 Python 中的详细使用方法:
序列化(编码)
json.dumps()
:将 Python 对象转换为 JSON 格式的字符串。支持的 Python 对象类型有字典、列表、元组、字符串、数字、布尔值和None
,转换规则为:字典转换为 JSON 对象,列表和元组转换为 JSON 数组,字符串、数字、布尔值和None
保持原有格式。
import json
data = {
"name": "Alice",
"age": 30,
"hobbies": ["reading", "traveling"]
}
json_str = json.dumps(data)
print(json_str)
json.dump()
:将 Python 对象序列化后写入到文件对象中。使用时需先打开文件,并指定合适的编码(通常为utf - 8
),操作完成后文件会自动关闭(若使用with
语句)。
import json
data = [1, 2, 3, 4]
with open('data.json', 'w', encoding='utf - 8') as f:
json.dump(data, f)
反序列化(解码)
json.loads()
:将 JSON 格式的字符串转换为 Python 对象。转换后的 Python 对象类型与原 JSON 数据结构对应,如 JSON 对象转换为 Python 字典,JSON 数组转换为 Python 列表。
import json
json_str = '{"name": "Bob", "age": 25, "is_student": false}'
data = json.loads(json_str)
print(data)
json.load()
:从文件对象中读取 JSON 数据并反序列化为 Python 对象。同样,使用with
语句打开文件,确保文件操作的安全性和规范性。
import json
with open('data.json', 'r', encoding='utf - 8') as f:
data = json.load(f)
print(data)
格式化输出:
在使用json.dumps()
时,可通过参数对输出的 JSON 字符串进行格式化,提高可读性。
indent
参数:指定缩进的空格数,使 JSON 字符串按层级结构缩进显示。
import json
data = {
"person": {
"name": "Charlie",
"details": {
"age": 35,
"city": "New York"
}
}
}
formatted_json = json.dumps(data, indent=4)
print(formatted_json)
separators
参数:用于指定 JSON 字符串中项与项、键与值之间的分隔符。默认分隔符是,
和:
,可根据需求调整。
import json
data = {"key1": "value1", "key2": "value2"}
custom_separators_json = json.dumps(data, separators=(',', ':'))
print(custom_separators_json)
处理特殊数据类型:
JSON 本身不支持所有 Python 数据类型,如日期时间、自定义类的实例等。处理这些特殊数据类型时,需要额外操作。
- 日期时间类型:先将日期时间对象转换为字符串,再进行 JSON 序列化。
import json
from datetime import datetime
now = datetime.now()
now_str = now.strftime('%Y-%m-%d %H:%M:%S')
data = {"time": now_str}
json_data = json.dumps(data)
print(json_data)
- 自定义类的实例:通过继承
json.JSONEncoder
类,并重写default()
方法,指定自定义类实例的序列化方式;反序列化时,利用object_hook
参数传入自定义函数解析 JSON 数据为自定义类实例。
import json
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class PointEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Point):
return {'x': o.x, 'y': o.y}
return super().default(o)
def point_decoder(dct):
if 'x' in dct and 'y' in dct:
return Point(dct['x'], dct['y'])
return dct
point = Point(1, 2)
json_str = json.dumps(point, cls=PointEncoder)
loaded_point = json.loads(json_str, object_hook=point_decoder)
print(loaded_point.x, loaded_point.y)
json.dumps函数详解
函数定义
json.dumps
函数用于将 Python 对象编码成 JSON 格式的字符串,其参数及用途如下:
参数名 | 含义 | 类型 | 默认值 |
---|---|---|---|
obj | 要转换为 JSON 字符串的 Python 对象,如字典、列表等 | 可序列化的 Python 对象 | 无 |
* | 这个表示在这个 仅限关键字 标记 * 之后的形参都必须以关键字参数形式传递该形参,不能是位置形参! | 仅限关键字参数 | * |
skipkeys | 若为 True ,当字典键不是基本类型(str 、int 、float 、bool 、None )时跳过该键;为 False 时遇非基本类型键会抛 TypeError 异常 | 布尔值 | False |
ensure_ascii | 为 True 时,非 ASCII 字符转义为 \uXXXX 形式;为 False 时,非 ASCII 字符原样输出 | 布尔值 | True |
check_circular | 为 True 时检查对象是否有循环引用,有则抛 ValueError 异常;为 False 不检查,可能导致无限递归 | 布尔值 | True |
allow_nan | 为 True 时允许在 JSON 中使用 NaN 、Infinity 和 -Infinity ;为 False 遇这些值抛 ValueError 异常 | 布尔值 | True |
cls | 自定义的 JSON 编码器类,用于处理特殊对象的序列化 | 类 | None |
indent | 指定缩进的整数或字符串,使生成的 JSON 更易读。整数表示空格数,字符串(如 '\t' )则用该字符串缩进 | 整数或字符串 | None |
separators | 元组 (item_separator, key_separator) ,指定 JSON 字符串中元素和键值对的分隔符 | 元组 | (', ', ': ') |
default | 处理无法直接序列化对象的函数,遇无法序列化对象时调用此函数 | 函数 | None |
sort_keys | 为 True 时,生成的 JSON 字符串中键按字典序排序 | 布尔值 | False |
**kw |
它允许函数调用时接收显式定义外的关键字参数,并传递给自定义编码器类。在函数内,可通过
| 无 | 无 |
**kw相关使用示例
import json
data = {'name': 'Alice', 'age': 30}
json_str = json.dumps(data, ensure_ascii=False, my_custom_param='value')
# 这里的my_custom_param就是通过**kw传递的额外参数
print(json_str)
在上述示例中,my_custom_param
就是通过 **kw
传递的额外参数。虽然在标准的 json.dumps()
函数中,并没有定义 my_custom_param
这个参数,但通过 **kw
可以接收并在函数内部进行相应的处理。不过在标准库的 json.dumps()
函数中,并不会对自定义的 my_custom_param
做任何处理,只是将其作为 kw
字典的一个键值对保存下来。如果是自定义的 dumps
函数,可以在函数内部对 kw
中的参数进行相应的逻辑处理。
json.dumps完整使用示例
import json
from datetime import datetime
# 自定义编码器处理日期对象
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
return super().default(obj)
# 定义一个包含多种类型数据的 Python 对象
data = {
'name': '张三',
'age': 25,
'is_student': True,
'grades': [90, 85, 92],
'birth_date': datetime(1999, 10, 15),
('tuple_key',): '特殊键值' # 非基本类型键
}
# 使用 json.dumps 函数进行转换
try:
json_str = json.dumps(
data,
skipkeys=True, # 跳过非基本类型的键
ensure_ascii=False, # 不转义非 ASCII 字符
check_circular=True, # 检查循环引用
allow_nan=True, # 允许 NaN 等特殊值
cls=CustomJSONEncoder, # 使用自定义编码器
indent=4, # 缩进 4 个空格
separators=(',', ':'), # 设置分隔符
default=None, # 这里使用自定义编码器,可不设置 default
sort_keys=True # 按键排序
)
print(json_str)
except (TypeError, ValueError) as e:
print(f"转换出错: {e}")
代码解释
- 自定义编码器
CustomJSONEncoder
:继承自json.JSONEncoder
,重写default
方法,处理datetime
对象的序列化。 - 定义数据对象
data
:包含字符串、整数、布尔值、列表、日期对象和非基本类型键。 - 调用
json.dumps
函数:设置多个参数进行转换,包括跳过非基本类型键、不转义非 ASCII 字符、使用自定义编码器等。 - 异常处理:捕获可能的
TypeError
和ValueError
异常并输出错误信息。
json.loads详解
json.loads函数定义:
json.loads
函数用于将 JSON 格式的字符串解析为 Python 对象,以下是其各个形参的详细介绍:
形参 | 类型 | 描述 | 默认值 |
---|---|---|---|
s | str | 必需参数,包含 JSON 数据的字符串,loads 函数会将其解析为对应的 Python 对象。 | 无 |
* | 这个表示在这个 仅限关键字 标记 * 之后的形参都必须以关键字参数形式传递该形参,不能是位置形参! | 仅限关键字参数 | * |
cls | class | 自定义的 JSON 解码器类。若提供该类,会使用此类进行 JSON 数据的解码操作。 | None |
object_hook | callable | 当解析到 JSON 对象(字典)时调用的函数。此函数接收一个字典作为参数,并返回一个 Python 对象,可用于对解析后的字典进行自定义处理。 | None |
parse_float | callable | 用于解析 JSON 中浮点数的函数。解析到浮点数时会调用该函数,它接收一个字符串参数,并返回一个 Python 浮点数对象,可自定义浮点数的解析方式。 | None |
parse_int | callable | 用于解析 JSON 中整数的函数。解析到整数时会调用该函数,它接收一个字符串参数,并返回一个 Python 整数对象,可自定义整数的解析方式。 | None |
parse_constant | callable | 用于解析 JSON 中常量(如 NaN 、Infinity 、-Infinity )的函数。解析到这些常量时会调用该函数,它接收常量对应的字符串作为参数,并返回一个 Python 对象。 | None |
object_pairs_hook | callable | 当解析到 JSON 对象(字典)时调用的函数,与 object_hook 不同的是,它接收一个由键值对元组组成的列表作为参数,常用于处理键重复的情况或需要保留键值对顺序的场景。 | None |
**kw | 可变关键字参数 | 接收其他额外的关键字参数,可传递给自定义的解码器类。 同json.dumps函数 | 无 |
json.loads
完整使用示例
import json
import math
# 自定义解码器类
class CustomDecoder(json.JSONDecoder):
def decode(self, s):
result = super().decode(s)
if isinstance(result, dict):
for key, value in result.items():
if isinstance(value, str):
result[key] = value.upper()
return result
# 自定义对象钩子函数
def custom_object_hook(dct):
if 'name' in dct:
dct['greeting'] = f"HELLO, {dct['name']}!"
return dct
# 自定义浮点数解析函数
def custom_parse_float(s):
return float(s) * 2
# 自定义常量解析函数
def custom_parse_constant(s):
if s == 'NaN':
return math.nan
elif s == 'Infinity':
return math.inf
elif s == '-Infinity':
return -math.inf
# 自定义对象对钩子函数
def custom_object_pairs_hook(pairs):
result = {}
for key, value in pairs:
if key in result:
result[key] = [result[key], value]
else:
result[key] = value
return result
# 包含 JSON 数据的字符串
json_str = '{"name": "John", "price": 9.99, "value": NaN, "name": "Doe"}'
# 使用 json.loads 进行解析
python_obj = json.loads(
json_str,
cls=CustomDecoder,
object_hook=custom_object_hook,
parse_float=custom_parse_float,
parse_constant=custom_parse_constant,
object_pairs_hook=custom_object_pairs_hook
)
print(python_obj)
代码解释
- 自定义解码器类
CustomDecoder
:对解析后的字典中的字符串值进行大写转换。 - 自定义对象钩子函数
custom_object_hook
:当解析结果包含name
键时,添加一个greeting
键。 - 自定义浮点数解析函数
custom_parse_float
:将解析到的浮点数乘以 2。 - 自定义常量解析函数
custom_parse_constant
:处理NaN
、Infinity
和-Infinity
常量。 - 自定义对象对钩子函数
custom_object_pairs_hook
:处理键重复的情况,将重复键的值合并为列表。 - 调用
json.loads
:传入自定义的解码器类和各个钩子函数,对 JSON 字符串进行解析。