如何在 Python 中处理 JSON 数据
Python json 模块基础
Python 内置的 json 模块是处理 JSON 的标准方式,无需安装额外依赖。它提供四个核心函数:json.loads()(字符串 → Python 对象)、json.dumps()(Python 对象 → 字符串)、json.load()(文件 → Python 对象)、json.dump()(Python 对象 → 文件)。这四个函数名的 s 代表 string,有 s 的操作字符串,没有 s 的操作文件对象——记住这个规律就不会混淆。
Python 的 JSON 类型映射:JSON 对象({})↔ Python 字典(dict);JSON 数组([])↔ Python 列表(list);JSON 字符串 ↔ Python str;JSON 数字 ↔ Python int 或 float;JSON true/false ↔ Python True/False;JSON null ↔ Python None。
import json
# 字符串解析 / String parsing
json_str = '{"name": "Alice", "age": 30, "active": true}'
data = json.loads(json_str)
print(data['name']) # "Alice"
print(data['active']) # True (Python bool, not string)
print(type(data)) #
# 序列化为字符串 / Serialize to string
obj = {"name": "Bob", "scores": [95, 87, 92]}
json_str = json.dumps(obj) # 紧凑 / Compact
pretty_str = json.dumps(obj, indent=2) # 格式化 / Pretty
sorted_str = json.dumps(obj, indent=2, sort_keys=True) # 键排序 / Sorted keys
unicode_str = json.dumps(obj, ensure_ascii=False) # 保留中文 / Preserve CJK
读写 JSON 文件
在 Python 中读写 JSON 文件是最常见的操作之一,使用 json.load() 和 json.dump() 配合 open() 上下文管理器:
import json
# 读取 JSON 文件 / Reading JSON file
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
# 写入 JSON 文件 / Writing JSON file
with open('output.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# 追加到 JSON Lines 文件(每行一个 JSON 对象)
# Append to JSON Lines file (one JSON object per line)
with open('data.jsonl', 'a', encoding='utf-8') as f:
f.write(json.dumps(new_record, ensure_ascii=False) + '\n')
# 读取 JSON Lines 文件 / Reading JSON Lines file
records = []
with open('data.jsonl', 'r', encoding='utf-8') as f:
for line in f:
if line.strip(): # 跳过空行 / Skip empty lines
records.append(json.loads(line))
自定义序列化:处理特殊类型
Python 的 json 模块默认不支持序列化 datetime、Decimal、UUID、自定义类等类型。可以通过自定义 JSONEncoder 或提供 default 函数来扩展:
import json
from datetime import datetime, date
from decimal import Decimal
from uuid import UUID
# 方法 1:使用 default 函数 / Method 1: Using default function
def extended_encoder(obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
if isinstance(obj, UUID):
return str(obj)
if hasattr(obj, '__dict__'):
return obj.__dict__
raise TypeError(f'Object of type {type(obj)} is not JSON serializable')
json.dumps(data, default=extended_encoder)
# 方法 2:自定义 JSONEncoder / Method 2: Custom JSONEncoder
class ExtendedEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return str(obj) # 精确金额用字符串 / Precise amounts as string
return super().default(obj)
json.dumps(data, cls=ExtendedEncoder, indent=2)
# 自定义解码(object_hook)/ Custom decoding (object_hook)
def datetime_decoder(dct):
for key, value in dct.items():
if isinstance(value, str) and 'T' in value:
try:
dct[key] = datetime.fromisoformat(value)
except ValueError:
pass
return dct
data = json.loads(json_str, object_hook=datetime_decoder)
使用 Pydantic 进行 JSON 数据验证
Pydantic 是 Python 生态中最流行的数据验证库,通过类型注解定义数据模型,自动验证 JSON 数据的类型和格式,并提供清晰的错误信息。它在 FastAPI 中被广泛使用:
from pydantic import BaseModel, EmailStr, validator
from typing import Optional, List
from datetime import datetime
class Address(BaseModel):
city: str
country: str
zip_code: Optional[str] = None
class User(BaseModel):
id: int
name: str
email: str
age: int
address: Address
tags: List[str] = []
created_at: datetime
@validator('age')
def validate_age(cls, v):
if v < 0 or v > 150:
raise ValueError('Age must be between 0 and 150')
return v
# 从 JSON 字符串解析并验证
# Parse and validate from JSON string
json_str = '''
{
"id": 1,
"name": "Alice",
"email": "[email protected]",
"age": 30,
"address": {"city": "Beijing", "country": "China"},
"created_at": "2025-01-01T00:00:00"
}
'''
user = User.model_validate_json(json_str) # Pydantic v2
# 或 / or:
# user = User.parse_raw(json_str) # Pydantic v1
# 序列化回 JSON
# Serialize back to JSON
print(user.model_dump_json(indent=2))
高性能 JSON 库:orjson
orjson 是 Python 性能最高的 JSON 库,用 Rust 实现,比标准 json 模块快 10 倍以上。它还原生支持 datetime、UUID、numpy 数组等类型,是处理大量 JSON 数据或高吞吐量应用的首选:
# 安装 / Install
# pip install orjson
import orjson
from datetime import datetime
from uuid import UUID
# 基本用法与 json 模块类似 / Basic usage similar to json module
data = {'name': 'Alice', 'created': datetime.now(), 'id': UUID('...')}
# 序列化(返回 bytes,不是 str)
# Serialize (returns bytes, not str)
json_bytes = orjson.dumps(data)
json_bytes = orjson.dumps(data, option=orjson.OPT_INDENT_2) # 格式化
# 反序列化(接受 str 或 bytes)
# Deserialize (accepts str or bytes)
data = orjson.loads(json_bytes)
# 性能对比(同等数据)/ Performance comparison (same data)
# json.dumps: ~1000 µs
# orjson.dumps: ~80 µs (约 12 倍速度 / ~12x faster)
# ujson 也是快速替代选项
# ujson is also a fast alternative option
# pip install ujson
import ujson
data = ujson.loads(json_str)
output = ujson.dumps(data, ensure_ascii=False, indent=2)
在 API 开发中处理 JSON
Python 中最流行的 API 框架 FastAPI 和 Flask 都内置了 JSON 支持。FastAPI(推荐用于新项目):基于 Pydantic 的自动 JSON 序列化/反序列化,自动生成 OpenAPI Schema;请求体自动解析为 Pydantic 模型,响应自动序列化:
# FastAPI 示例 / FastAPI example
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
name: str
email: str
class UserResponse(BaseModel):
id: int
name: str
email: str
@app.post('/users', response_model=UserResponse)
async def create_user(user: UserCreate):
# FastAPI 自动解析请求体为 UserCreate 对象
# FastAPI automatically parses request body as UserCreate object
new_user = save_to_db(user)
return new_user # 自动序列化为 JSON
# Flask 示例 / Flask example
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/users', methods=['POST'])
def create_user():
data = request.get_json() # 解析请求 JSON
if not data:
return jsonify({'error': 'Invalid JSON'}), 400
# 处理数据 / Process data
return jsonify({'id': 1, 'name': data['name']}), 201
JSON 与 Python dataclass 的集成
Python 3.7+ 引入的 dataclass 是组织数据结构的简洁方式,通过 dataclasses.asdict() 和 dataclasses.fields() 可以与 JSON 序列化集成:
对于 Python 3.10+,还可以使用 dataclasses.dataclass 配合 __post_init__ 进行验证,或者使用更新的 dataclass-wizard、cattrs 等库实现更完整的 JSON 序列化支持,包括嵌套对象的自动递归序列化和类型检查。这些工具在性能和功能性上比手动转换更可靠,尤其适合复杂数据模型的项目。
from dataclasses import dataclass, asdict, field
from typing import List
import json
@dataclass
class Address:
city: str
country: str
@dataclass
class User:
id: int
name: str
address: Address
tags: List[str] = field(default_factory=list)
# 序列化:dataclass → dict → JSON
# Serialize: dataclass → dict → JSON
user = User(id=1, name="Alice", address=Address(city="Beijing", country="China"))
user_dict = asdict(user) # 递归转换为字典
json_str = json.dumps(user_dict, ensure_ascii=False, indent=2)
# 反序列化:JSON → dict → dataclass(需手动处理嵌套)
# Deserialize: JSON → dict → dataclass (need to handle nesting manually)
data = json.loads(json_str)
address = Address(**data['address'])
user = User(**{**data, 'address': address})
立即免费使用相关工具
免费使用 →