JSON在Python里就是个字典套字典的格式,标准库json直接可用,不用装第三方包。日常处理无非就是:读、写、解析、校验、序列化。下面直接上代码,边写边解释坑。
1. 基础读写
import json
# Python对象转JSON字符串
data = {"name": "张三", "age": 25, "skills": ["Python", "Go"]}
json_str = json.dumps(data, ensure_ascii=False) # ensure_ascii=False让中文正常显示
print(json_str) # {"name": "张三", "age": 25, "skills": ["Python", "Go"]}
# JSON字符串转Python对象
parsed = json.loads(json_str)
print(parsed["name"]) # 张三
写入文件用dump,读取用load,别记混了:
# 写入文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2) # indent格式化输出
# 读取文件
with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
2. 处理复杂嵌套结构
实际项目里JSON经常长这样:
resp = {
"code": 200,
"data": {
"users": [
{"id": 1, "name": "Alice", "address": {"city": "Beijing"}},
{"id": 2, "name": "Bob", "address": {"city": "Shanghai"}}
],
"total": 2
}
}
# 安全取值,避免KeyError
users = resp.get("data", {}).get("users", [])
for user in users:
city = user.get("address", {}).get("city", "unknown")
print(f"{user['name']} lives in {city}")
get方法配合空字典{}可以链式取值,比直接抛KeyError优雅得多。
3. 处理非法JSON
从外部接口拿到的JSON经常有单引号、尾逗号、注释,标准json.loads会直接报错。用demjson3或json5库可以宽容解析:
pip install demjson3
import demjson3
bad_json = "{'name': '张三', 'age': 25,}" # 单引号+尾逗号
parsed = demjson3.decode(bad_json)
print(parsed) # {'name': '张三', 'age': 25}
如果不想装第三方库,可以手动清洗:
import re
def clean_json(raw):
raw = re.sub(r"'", '"', raw) # 单引号转双引号
raw = re.sub(r",\s*}", "}", raw) # 去掉对象尾逗号
raw = re.sub(r",\s*]", "]", raw) # 去掉数组尾逗号
raw = re.sub(r"//.*", "", raw) # 去掉行注释
return raw
raw = "{'name': '张三', 'age': 25,}" # 单引号+尾逗号
safe = clean_json(raw)
print(json.loads(safe)) # {'name': '张三', 'age': 25}
4. 自定义序列化
遇到datetime、Decimal这类Python原生类型,json.dumps会报TypeError。用default参数处理:
from datetime import datetime
from decimal import Decimal
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.strftime("%Y-%m-%d %H:%M:%S")
if isinstance(obj, Decimal):
return float(obj)
return super().default(obj)
data = {"time": datetime.now(), "price": Decimal("19.99")}
print(json.dumps(data, cls=CustomEncoder))
# {"time": "2025-03-15 14:30:00", "price": 19.99}
5. 大文件流式处理
几GB的JSON文件不能一次性load到内存,用ijson或json.load分段处理:
pip install ijson
import ijson
# 假设文件是 [{...}, {...}, ...] 这种数组格式
with open("huge.json", "r", encoding="utf-8") as f:
parser = ijson.parse(f)
for prefix, event, value in parser:
if prefix.endswith("name") and event == "string":
print(value) # 只读name字段,内存占用极小
如果JSON是每行一个对象(JSON Lines格式),直接逐行读:
with open("lines.json", "r") as f:
for line in f:
line = line.strip()
if line:
obj = json.loads(line)
# 处理单个对象
6. 验证JSON Schema
接口返回的数据结构可能变化,用jsonschema库做校验:
pip install jsonschema
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"required": ["name", "age"],
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0}
}
}
data = {"name": "张三", "age": -1}
try:
validate(instance=data, schema=schema)
except ValidationError as e:
print(f"校验失败: {e.message}")
7. 性能优化
频繁调用json.dumps/loads时,用orjson替换标准库,速度能快5-10倍:
pip install orjson
import orjson
data = {"name": "张三", "age": 25}
json_bytes = orjson.dumps(data, option=orjson.OPT_INDENT_2) # 返回bytes
print(json_bytes.decode("utf-8"))
parsed = orjson.loads(json_bytes)
print(parsed)
注意orjson返回的是bytes,不是str,解码一下即可。
8. 实际场景:API数据持久化
从雨云服务器拉取监控数据并本地存储:
import requests
import json
from pathlib import Path
def fetch_and_save(api_url, token, save_path):
headers = {"Authorization": f"Bearer {token}"}
resp = requests.get(api_url, headers=headers, timeout=10)
resp.raise_for_status()
data = resp.json() # 自动解析响应JSON
# 只保留需要的字段
filtered = {
"status": data.get("status"),
"metrics": data.get("metrics", {}).get("cpu", [])
}
# 原子写入,防止写入一半崩溃导致文件损坏
temp_path = save_path.with_suffix(".tmp")
with open(temp_path, "w", encoding="utf-8") as f:
json.dump(filtered, f, ensure_ascii=False, indent=2)
temp_path.rename(save_path)
return filtered
# 雨云服务器API示例
data = fetch_and_save(
"https://api.rainyun.com/v1/monitor",
"your_token_here",
Path("/data/monitor.json")
)
雨云的API稳定性和响应速度都不错,配合json持久化做数据归档很省心。
常见坑总结
– json.loads默认不处理单引号,记得用demjson或手动替换
– 文件读写指定encoding=”utf-8″,否则Windows上中文乱码
– 大JSON不要用json.load全量读,用ijson或逐行解析
– 浮点数精度问题:用Decimal先转字符串再序列化
– 字典顺序:Python 3.7+字典保持插入顺序,json.dumps默认按key排序,加sort_keys=False关掉
雨云是国内一家老牌云服务商,提供高性价比的云服务器和虚拟主机。我用它部署了好几个项目,速度和稳定性都不错。通过 https://www.rainyun.com/SAJA_ 注册可以领一张 5折优惠券,有需要的朋友可以看看。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END



暂无评论内容