Pickle与JSON:数据序列化的“兄弟”,却各有“脾气”
在数据存储、网络传输或程序间交互时,我们常需要将Python对象(如列表、字典、自定义类实例等)转换为可保存或传输的格式,这个过程称为“序列化”;反之,从格式化数据中还原对象的过程称为“反序列化”,在Python生态中,pickle和json是最常用的两种序列化工具,它们看似都能实现“对象→字节/字符串”的转换,实则从设计理念到使用场景都有着天壤之别,本文将从核心特性、数据类型支持、安全性等多个维度,拆解两者的“脾气”差异。
核心定位:Python“亲儿子” vs 通用“外交官”
Pickle:Python的“专属序列化协议”
pickle是Python内置的模块,它的诞生只有一个目的——在Python生态中无缝保存和还原对象,你可以把它理解为Python的“私人管家”,专门为Python对象量身定制:无论是简单的列表、字典,还是复杂的自定义类实例、函数、甚至Python代码本身,pickle都能尝试将其“打包”成字节流,并在需要时“解包”还原成原始对象,这种“全家桶”式的支持,得益于它直接使用Python的字节码协议,深度绑定Python解释器。
JSON:跨语言的“通用数据交换格式”
JSON(JavaScript Object Notation)则是一个与语言无关的轻量级数据交换格式,最初脱胎于JavaScript,如今已成为互联网领域的“通用语”,它的设计目标是让不同编程语言(如Python、Java、JavaScript、C++等)能轻松读写数据,JSON以文本形式存储数据,结构简单(仅支持对象、数组、字符串、数字、布尔值、null),可读性强,就像一个“外交官”,专门负责在不同语言之间传递“标准化信息”。
数据类型支持:“万物皆可Pickle” vs “仅限JSON原生类型”
两者最直观的区别,在于对Python对象类型的支持广度。
Pickle:几乎支持所有Python对象
pickle的“包容性”极强,它能处理Python的大部分内置对象,甚至包括:
- 自定义类实例:只要类在当前环境中定义,
pickle能保存实例的属性(包括__dict__中的所有数据),反序列化时自动重建对象。 - 函数与代码:可以保存函数、lambda表达式,甚至Python代码片段(通过
pickle的REDUCE协议)。 - Python特有的复杂类型如集合(
set)、元组(tuple)、日期时间(datetime)等,都能被直接序列化。
一个自定义的Person类实例:
import pickle
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Alice", 25)
data = pickle.dumps(p) # 序列化为字节流
p_loaded = pickle.loads(data) # 反序列化为对象
print(p_loaded.name) # 输出: Alice
pickle能完整保存Person对象的属性,无需额外操作。
JSON:仅支持原生基础类型
JSON的数据类型是“跨语言最小公约数”,仅支持6种类型:object(类似Python字典)、array(类似Python列表)、string、number、boolean、null,对于Python特有的类型(如set、tuple、datetime),JSON无法直接处理,需要手动转换:
tuple→ 转换为list(反序列化时需手动转回);set→ 转换为list;datetime→ 转换为字符串(如ISO 8601格式);- 自定义类实例 → 无法直接序列化,需转换为字典或JSON支持的类型。
用JSON处理Person类时,必须先“拆解”为字典:
import json
from datetime import datetime
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Bob", 30)
# 手动转换为字典
data = {"name": p.name, "age": p.age}
json_str = json.dumps(data) # 序列化为JSON字符串
loaded_data = json.loads(json_str) # 反序列化为字典
# 需手动重建对象(若需)
p_loaded = Person(loaded_data["name"], loaded_data["age"])
若直接对p调用json.dumps(),会抛出TypeError:Object of type Person is not JSON serializable。
数据格式:二进制“黑盒” vs 文本“明文”
Pickle:二进制字节流,可读性差
pickle序列化后的数据是二进制格式(默认使用pickle协议4或5),包含Python特定的字节码指令,这种格式对人类完全不可读,就像一个“黑盒”:
import pickle
data = {"name": "Charlie", "scores": [90, 85, 88]}
pickle_data = pickle.dumps(data)
print(pickle_data) # 输出: b'\x80\x04\x95\x15\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x07Charlie\x94\x94\x8c\x06scores\x94]\x94(K\x5aK\x55K\x58e.'
一堆乱码般的字节,完全无法直观理解内容。
JSON:文本字符串,可读性强
JSON序列化后是人类可读的文本字符串,结构清晰(键值对用,数组用[]),可直接用文本编辑器查看或修改:
import json
data = {"name": "Charlie", "scores": [90, 85, 88]}
json_str = json.dumps(data, indent=2) # indent=2格式化,更易读
print(json_str)
输出:
{
"name": "Charlie",
"scores": [
90,
85,
88
]
}
这种“明文”特性,让JSON非常适合配置文件、日志存储等需要人工干预的场景。
安全性与跨语言:“亲儿子”的“信任危机” vs “外交官”的“安全底线”
Pickle:不安全,仅限Python内部使用
pickle的“万物皆可序列化”特性,也带来了严重的安全隐患,反序列化pickle数据时,Python会执行序列化数据中包含的任意代码,如果pickle数据来自不可信来源(如网络请求、用户上传),攻击者可能构造恶意数据,在反序列化时执行系统命令、删除文件等恶意操作。
以下恶意pickle数据会在反序列化时执行rm -rf /(Linux系统):
import pickle
import os
class Malicious:
def __reduce__(self):
return os.system, ("rm -rf /",)
malicious_data = pickle.dumps(Malicious())
# 若将malicious_data存入文件,其他用户用pickle.loads加载,可能触发系统命令
pickle绝对不能用于处理来自不可信来源的数据!它只适用于“可信环境”(如同一台机器上的Python进程间通信、本地文件存储)。
JSON:安全,跨语言无风险
JSON的设计初衷是“数据交换”,而非“代码执行”,它只支持静态数据结构,反序列化时不会执行任何代码,无论数据来自哪个语言、哪个来源,JSON解析器只会将其视为纯数据,安全性远高于pickle。
即使JSON字符串中包含类似函数的字符串:
{"name": "attacker", "cmd": "rm -rf /"}
解析后也只是得到一个字典,"cmd"的值会被当作普通字符串,不会被执行,这种“只读数据”的特性,让JSON成为网络API、Web应用数据交换的首选。
性能与场景:快速“内传” vs 稳定“外联”
Pickle:Python内部通信的“加速器”
由于pickle是二进制格式,且深度优化了Python对象的序列化/反序列化逻辑,它在Python内部场景中性能更优:
- 序列化速度更快(二进制比文本更紧凑);
- 支持复杂对象,无需手动转换,适合保存Python程序运行时的状态(如机器学习模型的
sklearn对象、爬虫的Scrapy数据管道等)。
典型场景:
- 本地保存Python对象(如缓存、模型持久化);
- 同一台机器上多个Python进程间的数据传递(通过管道、共享内存)。
JSON:跨语言数据交换的“通用桥”
JSON的文本格式虽然比



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