Python怎么读取JSON数据:从入门到实践
在Python开发中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,因其易读、易解析的特性,被广泛应用于API接口、配置文件、数据存储等场景,Python读取JSON数据的方法,是处理结构化数据的基础技能,本文将详细介绍Python中读取JSON数据的多种方式,从基础操作到进阶技巧,帮助你全面这一技能。
JSON与Python的天然契合:为什么选择JSON?
JSON是一种文本格式,采用键值对(key-value)的方式组织数据,支持字符串、数字、布尔值、数组、对象(字典)等数据类型,这些结构与Python中的基本数据类型高度对应:
- JSON对象 → Python字典(dict)
- JSON数组 → Python列表(list)
- JSON字符串 → Python字符串(str)
- JSON数字(整数/浮点数)→ Python整数(int)/浮点数(float)
- JSON布尔值(true/false)→ Python布尔值(True/False)
- JSON空值(null)→ Python空值(None)
这种天然的对应关系,让Python处理JSON数据变得异常简单,而Python内置的json模块,则提供了完整的JSON解析与生成功能,无需额外安装库即可使用。
核心方法:json模块的基础读取操作
Python的json模块是处理JSON数据的“瑞士军刀”,其中最常用的读取函数是json.loads()和json.load(),两者功能相似,使用场景不同。
从字符串读取JSON:json.loads()
当你需要解析的JSON数据以字符串形式存在(例如从API响应、用户输入或文本文件中读取的字符串),可以使用json.loads()(loads = load string,加载字符串)。
基本语法
import json
json_string = '{"name": "张三", "age": 25, "is_student": false, "courses": ["Python", "JavaScript"]}'
data = json.loads(json_string)
print(data)
输出结果
{'name': '张三', 'age': 25, 'is_student': False, 'courses': ['Python', 'JavaScript']}
关键点说明
- 输入必须是合法的JSON格式字符串(注意:JSON字符串中的双引号会被解析为Python字符串的单引号,但底层仍是字符串类型)。
- 如果JSON字符串格式错误(如缺少引号、逗号使用不当等),会抛出
json.JSONDecodeError异常。
示例:处理异常
invalid_json_string = '{"name": "李四", "age": 30,}' # 末尾有多余逗号
try:
data = json.loads(invalid_json_string)
except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
# 输出:JSON解析失败: Expecting property name enclosed in double quotes: line 1 column 24 (char 23)
从文件读取JSON:json.load()
如果JSON数据存储在文件中(例如.json配置文件、数据导出文件等),可以使用json.load()(load = 从文件加载,无s),基本步骤是:先以文本模式打开文件,再调用json.load()解析文件对象。
基本语法
假设有一个data.json如下:
{
"city": "北京",
"population": 21540000,
"landmarks": ["故宫", "天安门", "长城"],
"is_capital": true
}
读取该文件的Python代码:
import json
with open('data.json', 'r', encoding='utf-8') as file: # 必须以文本模式打开('r')
data = json.load(file)
print(data)
输出结果
{'city': '北京', 'population': 21540000, 'landmarks': ['故宫', '天安门', '长城'], 'is_capital': True}
关键点说明
- 文件必须以文本模式打开(
'r',默认编码为UTF-8,建议显式指定encoding='utf-8'以避免中文乱码)。 - 如果文件内容不是合法的JSON格式,同样会抛出
json.JSONDecodeError异常。 - 使用
with open()可以确保文件在读取后自动关闭,避免资源泄漏。
进阶技巧:处理复杂JSON与自定义解析
实际场景中,JSON数据可能更复杂(如嵌套结构、特殊格式),或需要自定义解析逻辑,此时可以通过以下技巧灵活处理。
处理嵌套JSON
JSON数据常嵌套多层(如对象中嵌套数组,数组中嵌套对象),Python的字典和列表可以天然表示这种嵌套结构,直接通过索引或键访问即可。
示例
json_string = '''
{
"school": "清华大学",
"departments": [
{
"name": "计算机系",
"courses": ["人工智能", "数据结构"],
"head": {"name": "王教授", "title": "系主任"}
},
{
"name": "物理系",
"courses": ["量子力学", "热力学"],
"head": {"name": "李教授", "title": "系主任"}
}
]
}
'''
data = json.loads(json_string)
# 访问嵌套数据
print(data["school"]) # 输出:清华大学
print(data["departments"][0]["name"]) # 输出:计算机系
print(data["departments"][0]["head"]["title"]) # 输出:系主任
自定义JSON解码器(处理特殊数据类型)
默认情况下,json模块只能解析基本数据类型,如果JSON中包含Python没有直接对应的数据类型(如datetime、Decimal等),需要自定义解码器。
示例:解析包含日期的JSON
假设JSON字符串中有一个日期字段"created_at": "2023-10-01T12:00:00",希望将其解析为Python的datetime对象。
from datetime import datetime
import json
# 自定义解码器函数
def custom_decoder(dct):
if "created_at" in dct:
dct["created_at"] = datetime.fromisoformat(dct["created_at"])
return dct
json_string = '{"id": 1, "title": "Python教程", "created_at": "2023-10-01T12:00:00"}'
data = json.loads(json_string, object_hook=custom_decoder)
print(data)
print(data["created_at"]) # 输出:2023-10-01 12:00:00
print(type(data["created_at"])) # 输出:<class 'datetime.datetime'>
说明
object_hook参数是一个函数,会在每个JSON对象被解析后调用,传入解析后的字典(dct),可以修改字典内容并返回。- 通过
object_hook,可以灵活处理需要特殊转换的字段。
处理大型JSON文件(流式读取)
如果JSON文件非常大(如几GB),直接使用json.load()可能会占用过多内存,此时可以逐行或分块读取文件,结合json.JSONDecoder进行流式解析。
示例:逐行读取JSON Lines(.jsonl)文件
JSON Lines是一种每行一个JSON对象的格式,适合存储大量结构化数据,可以使用json.loads()逐行解析:
import json
# 假设有一个data.jsonl文件,内容如下:
# {"name": "用户1", "age": 20}
# {"name": "用户2", "age": 25}
# {"name": "用户3", "age": 30}
with open('data.jsonl', 'r', encoding='utf-8') as file:
for line in file:
data = json.loads(line.strip()) # 去除换行符
print(f"用户名: {data['name']}, 年龄: {data['age']}")
输出结果
用户名: 用户1, 年龄: 20
用户名: 用户2, 年龄: 25
用户名: 用户3, 年龄: 30
说明
- 流式读取适用于“每行一个独立JSON对象”的场景,内存占用低,适合处理海量数据。
- 如果JSON文件是一个整体(非逐行结构),流式解析较复杂,可考虑使用
ijson库(第三方库,需安装:pip install ijson)。
常见问题与解决方案
中文乱码问题
现象:读取JSON文件时,中文字符显示为"\u4e2d\u6587"。
原因:文件编码与解析编码不一致(如文件实际是UTF-8,但打开时未指定encoding='utf-8')。
**



还没有评论,来说两句吧...