Python的秘密生活:Pickle罐

发布: (2026年3月1日 GMT+8 05:45)
4 分钟阅读
原文: Dev.to

Source: Dev.to

为什么会出现 “Cannot Pickle”:Python 序列化的限制

当你尝试复制或序列化某些对象——例如活跃的数据库连接、文件句柄或网络套接字——时,Python 会抛出类似 “cannot pickle …”TypeError。此错误源于 pickle 模块的根本限制:它只能序列化完全位于 Python 内存中的数据。

什么是 Pickling?

Pickling 是 Python 对 序列化 的称呼:将内存中的对象转换为扁平的字节流,以便写入文件、通过网络传输或用于深拷贝。

import pickle

data = {"matches": 10, "active": True}
pickled_data = pickle.dumps(data)

print(pickled_data)
  • pickle.dumps() 返回一个字节对象(例如 b'\x80\x04\x95\x11...'),它代表原始数据。
  • pickle.loads() 则执行相反的过程,重建一个等价于原始对象的新实例。

pickle 模块记录每个对象的类型、属性以及原始数据。反序列化时,Python 按照这些记录的指令重新构建对象。

为什么有些对象无法被 Pickle

依赖操作系统管理资源的对象——例如:

  • 文件描述符(打开的文件)
  • 网络套接字(活跃的连接)
  • 数据库连接

其状态仅在操作系统持有底层资源时才有意义。序列化原始描述符(如套接字编号)在以后将毫无用处,因为操作系统可能已将该编号重新分配给其他进程。因此,pickle 拒绝序列化此类对象并抛出 TypeError

Pickle 与其他格式的对比

功能PickleJSON
语言特定性仅限 Python语言无关
支持的类型几乎所有 Python 对象(包括自定义类)基本类型:字符串、数字、布尔值、列表、字典
人类可读否(二进制)是(文本)
安全性反序列化时可执行任意代码安全(不执行代码)

如果需要与 JavaScript、Go 或其他语言编写的程序交换数据,JSON(或 MessagePack 等可互操作的格式)通常是更好的选择。

安全考虑

永远不要反序列化来自不可信来源的数据。
在反序列化过程中,Python 会执行字节流中存储的指令。恶意负载可以嵌入自动运行的代码,从而导致任意代码执行。

仅在你自己创建或已验证、可信的来源提供的数据上调用 pickle.loads()

高级技巧:自定义序列化

对于需要特殊处理的类,实现 __reduce__(或 __reduce_ex__)方法。该方法告诉 pickle 如何序列化和重建对象。

class MyClass:
    def __init__(self, value):
        self.value = value

    def __reduce__(self):
        # 返回一个可调用对象及其参数,用于重新创建该对象
        return (self.__class__, (self.value,))

小结

  • Pickling = 将对象序列化为 Python 特定的字节流。
  • Unpickling = 将字节流反序列化回 Python 对象。
  • 边界:受操作系统管理的资源(文件、套接字、数据库连接)无法被 pickle。
  • 替代方案:跨语言数据交换时使用 JSON。
  • 安全规则:仅反序列化可信数据。
  • 自定义:通过实现 __reduce__ 获得对序列化过程的细粒度控制。
0 浏览
Back to Blog

相关文章

阅读更多 »

不糟糕的语义失效

缓存问题 如果你在 Web 应用上工作了一段时间,你就会了解缓存的情况。你加入缓存,一切都变快了,然后有人……

按组反转数组

问题描述:将数组按给定大小 k 分组后逆序。数组被划分为长度为 k 的连续块(窗口),每个块都被逆序。