Python 标准库中的数据存储与序列化:jsonpicklecsv

当需要将数据写入文件或通过网络传输时,序列化(Serialization) 是必不可少的步骤。Python 为此提供了三种截然不同的标准工具:jsonpicklecsv

数据传输格式供应商

  • json:可读的文本格式,跨语言交换友好
  • pickle:将 Python 对象原样保存的二进制格式,功能强大但存在安全隐患
  • csv:最简洁的文本格式,用于表格(表)数据,通用性高

本文将根据“想要存储或使用的数据类型”来整理选择这三种模块的思路。


1. JSON

1.1 概述

JSON(JavaScript Object Notation)是基于文本语言无关的格式。它广泛用于配置文件、API 响应/请求、日志等“与其他系统交互”的场景。在 Python 中直接使用 json 模块即可处理。

1.2 核心 API(常用)

  • json.dump(obj, fp, ...) / json.load(fp, ...):文件读写
  • json.dumps(obj, ...) / json.loads(s, ...):字符串转换/恢复

值得记住的选项:

  • ensure_ascii=False:不对非 ASCII 字符进行转义,保持原文
  • indent=2:美化输出
  • default=...:为 JSON 不认识的类型提供自定义转换

1.3 使用示例(基本)

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 的“类型限制”

JSON 原生只支持 dictliststrint/floatboolNone。例如 datetime 无法直接序列化。此时可以使用 default 参数。

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 优缺点

优点

  • 语言无关,易于交换/共享
  • 文本格式,易于调试和版本控制
  • pickle 不同,加载时不会执行代码

缺点

  • 类型表达有限(如 datetimesetDecimal、二进制数据)
  • 对大数据而言,体积和速度可能不如二进制格式

2. Pickle

2.1 概述

picklePython 对象原样保存 的序列化方式。其结果是二进制数据(bytes),加载后几乎恢复为原始对象。

pickle 特别适用于:

  • 想保存复杂的 Python 对象(自定义类实例、嵌套结构、训练好的模型等)
  • 不需要与其他语言共享数据

相反,以下情况应避免使用:

  • 需要从不可信来源加载数据(pickle.load() 可能执行恶意代码)
  • 与其他语言/系统交换数据

2.2 核心 API(最常用 4 个)

  • pickle.dump(obj, file, protocol=...):对象 → 文件(二进制)
  • pickle.load(file):文件 → 对象
  • pickle.dumps(obj, protocol=...):对象 → bytes
  • pickle.loads(data):bytes → 对象
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 是什么,为什么要关注?

protocol 是 pickle 存储数据的 格式版本。不同版本会影响文件大小、速度和支持的功能。

  • 未指定时,Python 选择“当前环境下最合适的默认值”。
  • 通常保持默认即可。
  • 需要手动指定时,主要有两种情况: 1. 与旧 Python 版本兼容(使用较低协议) 2. 追求文件大小/速度最优(使用最高协议)
import pickle

with open("data.pkl", "wb") as f:
    pickle.dump({"x": 1}, f, protocol=pickle.HIGHEST_PROTOCOL)

2.4 Pickle 的真正注意点(重要)

pickle.load() / pickle.loads() 会执行数据中包含的 恢复逻辑。因此,从不可信来源加载 pickle 可能导致意外行为。

  • 安全做法:不要打开未知来源的 .pkl 文件
  • 若需共享/交换,优先使用 json 等文本格式。

2.5 优缺点

优点

  • 能保存几乎所有 Python 对象
  • 通常比 json 更快、更简洁(尤其是复杂对象)

缺点

  • 安全风险(不可信数据不可加载)
  • 仅 Python 可读,无法与其他语言共享
  • 类定义变更可能导致旧 pickle 无法加载

3. CSV

3.1 概述

CSV(Comma-Separated Values)是最简单的表格数据格式。常见于电子表格、数据导入/导出、日志转储等场景。

3.2 核心 API(常用)

  • csv.reader / csv.writer:基于列表
  • csv.DictReader / csv.DictWriter:基于字典(更常用)

3.3 使用示例(DictWriter/DictReader)

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 的三大注意点

  1. 一定要使用 newline="":尤其在 Windows 上避免双行换行。
  2. 所有字段默认是字符串:读取后需手动转换。
  3. 分隔符/引号/换行可能出现在数据中:使用 csv 模块可安全处理。

3.5 优缺点

优点

  • 极轻量,几乎所有工具都能读写
  • 对表格数据非常直观

缺点

  • 难以表达嵌套结构(列表/字典嵌套)
  • 缺少类型信息,需手动转换

4. 比较与选择指南

项目 JSON Pickle CSV
语言兼容 非常好 仅 Python 非常好
可读性 低(二进制)
类型表达 限制 极高 限制
安全性 相对安全 需谨慎 相对安全
数据结构 树形(嵌套) “Python 对象原样” 表格(行/列)

一句话总结:

  • 与其他系统交互json
  • 完整保存 Python 对象pickle(但要严格控制来源)
  • 行/列导出csv

5. 同一数据三种存储/恢复示例

以下示例展示如何使用 jsonpicklecsv 对同一数据进行存储和读取。

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. 结语

仅凭 Python 标准库,就能覆盖数据存储与序列化的广泛需求。

  • 需要跨语言共享json
  • 想保留完整 Python 对象pickle
  • 想以表格形式导出csv

根据数据形态与目的选择合适的模块,即可快速、干净地完成存储与恢复。