# Python 标准库中的数据存储与序列化:`json`、`pickle`、`csv` 当需要将数据写入文件或通过网络传输时,**序列化(Serialization)** 是必不可少的步骤。Python 为此提供了三种截然不同的标准工具:**`json`**、**`pickle`**、**`csv`**。 ![数据传输格式供应商](/media/editor_temp/6/82b2d285-16b0-473a-b88a-cd9a6f6582f2.png) * **`json`**:可读的文本格式,便于跨语言交换 * **`pickle`**:一种能将 Python 对象原样保存的二进制格式,功能强大但存在安全隐患 * **`csv`**:最简洁的文本格式,常用于表格数据,通用性高 本文将根据“想要存储或使用的数据类型”来阐述这三种模块的选择思路。 --- ## 1. JSON {#sec-c0452ee3f8b9} ### 1.1 概述 {#sec-573894aef250} JSON(JavaScript Object Notation)是**基于文本**且**语言无关**的格式。它广泛用于配置文件、API 响应/请求、日志等“与其他系统交互”的场景。在 Python 中直接使用 `json` 模块即可处理。 ### 1.2 核心 API(常用) {#sec-7388e1478aff} * `json.dump(obj, fp, ...)` / `json.load(fp, ...)`:文件读写 * `json.dumps(obj, ...)` / `json.loads(s, ...)`:字符串转换/恢复 值得记住的选项: * `ensure_ascii=False`:不对非 ASCII 字符进行转义,保留原文 * `indent=2`:格式化输出 * `default=...`:为 JSON 不认识的类型提供自定义转换 ### 1.3 使用示例(基本) {#sec-57d0c0653337} ```python import json data = { "name": "Alice", "age": 30, "skills": ["Python", "Data Science"] } with open("data.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) with open("data.json", "r", encoding="utf-8") as f: loaded = json.load(f) print(loaded) ``` ### 1.4 解决 JSON 的“类型限制” {#sec-a43d0fe8a199} JSON 原生只支持 `dict`、`list`、`str`、`int/float`、`bool`、`None`。例如 `datetime` 无法直接序列化。这时可以使用 `default` 参数。 ```python import json from datetime import datetime, timezone payload = {"created_at": datetime.now(timezone.utc)} def to_jsonable(obj): if isinstance(obj, datetime): return obj.isoformat() raise TypeError(f"Not JSON serializable: {type(obj)!r}") s = json.dumps(payload, default=to_jsonable, ensure_ascii=False) print(s) ``` ### 1.5 优缺点 {#sec-667d6fad184b} **优点** * 语言无关,易于交换/共享 * 文本格式,易于调试和版本控制 * 与 `pickle` 不同,加载时不会执行代码 **缺点** * 类型表达有限(如 `datetime`、`set`、`Decimal`、二进制数据) * 对大数据而言,体积和速度可能不如二进制格式 --- ## 2. Pickle {#sec-7417b1955ccc} ### 2.1 概述 {#sec-1889607ea8cb} `pickle` 是一种 **将 Python 对象原样保存** 的序列化方式。其结果是二进制数据(bytes),加载后几乎恢复为原始对象。 `pickle` 特别适用于: * 想保存复杂的 Python 对象(自定义类实例、嵌套结构、训练好的模型等) * 不需要与其他语言共享数据 相反,以下情况应避免使用: * 需要从不可信来源加载数据(`pickle.load()` 可能执行恶意代码) * 与其他语言/系统交换数据 --- ### 2.2 核心 API(最常用 4 个) {#sec-a0a97fe87a25} * `pickle.dump(obj, file, protocol=...)`:对象 → 文件(二进制) * `pickle.load(file)`:文件 → 对象 * `pickle.dumps(obj, protocol=...)`:对象 → bytes * `pickle.loads(data)`:bytes → 对象 ```python import pickle data = {"a": [1, 2, 3], "b": ("x", "y")} with open("data.pkl", "wb") as f: pickle.dump(data, f) with open("data.pkl", "rb") as f: loaded = pickle.load(f) print(loaded) ``` --- ### 2.3 `protocol` 是什么,为什么要关注? {#sec-1f8e5565848c} `protocol` 是 pickle 用于存储数据的 **格式版本**。不同版本会影响文件大小、速度和支持的功能。 * 未指定时,Python 会选择“当前环境中最合适的默认值”。 * 通常保持默认即可。 * 需要手动指定时,主要有两种情况: 1. 与旧 Python 版本兼容(使用较低协议) 2. 追求文件大小/速度最优(使用最高协议) ```python import pickle with open("data.pkl", "wb") as f: pickle.dump({"x": 1}, f, protocol=pickle.HIGHEST_PROTOCOL) ``` ### 2.4 Pickle 的真正注意点(重要) {#sec-007b70a5e9ec} `pickle.load()` / `pickle.loads()` 会执行数据中包含的**恢复逻辑**。因此,**从不可信来源加载 pickle** 可能导致意外行为。 * 安全做法:**不要打开未知来源的 `.pkl` 文件**。 * 若需共享/交换,优先使用 `json` 等文本格式。 ### 2.5 优缺点 {#sec-bbd5a24bec31} **优点** * 能保存几乎所有 Python 对象 * 通常比 `json` 更快、更简洁(尤其是复杂对象) **缺点** * 安全风险(不可信数据不可加载) * 仅 Python 可读,无法与其他语言共享 * 类定义变更可能导致旧的 pickle 文件无法加载 --- ## 3. CSV {#sec-99e590b24e50} ### 3.1 概述 {#sec-1265cc44a461} CSV(Comma-Separated Values)是最简单的表格数据格式。常见于电子表格、数据导入/导出、日志转储等场景。 ### 3.2 核心 API(常用) {#sec-5b2e4c37cce5} * `csv.reader` / `csv.writer`:基于列表 * `csv.DictReader` / `csv.DictWriter`:基于字典(更常用) ### 3.3 使用示例(DictWriter/DictReader) {#sec-524921270351} ```python import csv data = [ {"name": "Alice", "age": 30, "city": "Seoul"}, {"name": "Bob", "age": 25, "city": "Busan"}, ] with open("people.csv", "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=["name", "age", "city"]) writer.writeheader() writer.writerows(data) with open("people.csv", "r", encoding="utf-8") as f: reader = csv.DictReader(f) loaded = list(reader) print(loaded) ``` ### 3.4 CSV 的三大注意点 {#sec-3db1b7ed8444} 1. **一定要使用 `newline=""`**:尤其在 Windows 系统上,可避免双行换行。 2. **所有字段默认是字符串**:读取后需手动转换。 3. **分隔符/引号/换行可能出现在数据中**:使用 `csv` 模块可安全处理。 ### 3.5 优缺点 {#sec-6a8ca4891a8e} **优点** * 极轻量,几乎所有工具都能读写 * 对表格数据非常直观 **缺点** * 难以表达嵌套结构(列表/字典嵌套) * 缺少类型信息,需手动转换 --- ## 4. 比较与选择指南 {#sec-6304ec188cc0} | 项目 | JSON | Pickle | CSV | |------|------|--------|-----| | 语言兼容 | 非常好 | 仅 Python | 非常好 | | 可读性 | 高 | 低(二进制) | 高 | | 类型表达 | 限制 | 极高 | 限制 | | 安全性 | 相对安全 | **需谨慎** | 相对安全 | | 数据结构 | 树形(嵌套) | “Python 对象原样” | 表格(行/列) | 一句话总结: * **与其他系统交互** → `json` * **完整保存 Python 对象** → `pickle`(但要严格控制来源) * **行/列导出** → `csv` --- ## 5. 同一数据三种存储/恢复示例 {#sec-21f8c2a6d6c9} 以下示例展示如何使用 `json`、`pickle`、`csv` 对同一数据进行存储和读取。 ```python import json, pickle, csv data = [ {"id": 1, "name": "Alice", "score": 95.5}, {"id": 2, "name": "Bob", "score": 88.0}, ] # 1) JSON with open("data.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) with open("data.json", "r", encoding="utf-8") as f: json_loaded = json.load(f) # 2) Pickle with open("data.pkl", "wb") as f: pickle.dump(data, f) with open("data.pkl", "rb") as f: pickle_loaded = pickle.load(f) # 3) CSV with open("data.csv", "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=["id", "name", "score"]) writer.writeheader() writer.writerows(data) with open("data.csv", "r", encoding="utf-8") as f: reader = csv.DictReader(f) csv_loaded = [ {"id": int(row["id"]), "name": row["name"], "score": float(row["score"])} for row in reader ] print(json_loaded) print(pickle_loaded) print(csv_loaded) ``` 要点: * CSV 读取后需手动转换类型。 * Pickle 方便但需谨慎管理加载来源。 --- ## 6. 结语 {#sec-f88db3766ed6} 仅凭 Python 标准库,便能满足数据存储与序列化的广泛需求。 * **需要跨语言共享** → `json` * **想保留完整 Python 对象** → `pickle` * **想以表格形式导出** → `csv` 根据数据形态与目的选择合适的模块,即可快速高效地完成存储与恢复。