为什么不使用pickle而不是struct?

deb*_*ish 3 python struct pickle

我无法理解使用pickle模块还是使用struct模块。两者都将Python对象转换为字节流。它似乎pickle比包装和拆包struct模块容易。那么何时pickle使用和何时struct使用?

Ser*_*sta 6

因为他们做的事情完全不同。

您可以通过不同的方式序列化对象:

  • 文本序列化格式:这里序列化的对象是人类可读的。常见格式为 json 和 xml,或用于简单行列表的 csv 。但是除了非常简单的对象(数组、字典和简单数据)之外,您需要定义一个编组协议来保存对象的相关部分,然后从其序列化版本重建对象
  • 二进制序列化格式:
    • pickle 的目的是自动序列化一个对象,并允许它自动反序列化回来,前提是该类在反序列化时可用。它的主要缺点是只能在 Python 中使用
    • struct 则相反:您必须具体决定保存什么内容以及以什么格式保存。并且在反序列化时,您还必须知道使用了什么格式。但它可以用于与任何其他语言交换二进制流,只要格式明确定义

TL/DR 问题不在于性能(即使某些转换可能比其他转换稍微消耗更多资源),而更多在于序列化的目标:用于本地备份的 pickle 、用于外部交换的结构


Wil*_*sem 5

我认为您对功能有误解struct

结构

Struct 并不意味着将Python对象存储到字节流中。它所做的是通过 Python 对象转换成表示对象所包含数据结构来产生字节流。例如,使用带符号的32位表示形式表示整数。但是,例如a 并非旨在存储字典,因为有很多方法可以序列化字典。struct

它用于构建符合协议标准的(二进制)文件。例如,如果您具有3D模型,则您可能想要将导出器写入.3ds文件格式。此格式遵循一定的协议(例如,其将开始与0x4d4d)。您不能使用pickle来转储为这种格式,因为Pickle实际上是一个特定的协议。

将二进制文件读入Python对象也是如此。你不能在运行味酸.3ds文件,因为泡菜不知道协议。它不知道是什么0x4d4d的文件手段的开始。它可以是16位整数(19789),也可以是2个字符的ASCII字符串('MM')等),通常大多数二进制文件都是出于一种目的而设计的,并且您需要了解协议才能读取/写入此类文件。

泡菜

另一方面,Pickle是一种旨在将Python对象存储在二进制流中的工具,这样我们就可以在需要这些对象时将其重新加载。它定义了一个协议。例如泡菜总是开始于字节的流128,随后的协议版本(12,或3)。下一个字节指定将要腌制的对象类型的标识符(例如75,整数,88字符串等)。

Pickle还必须序列化该对象的所有引用,并跟踪已序列化的对象,因为其中可能包含循环结构。例如,如果我们有两个字典:

d = {}
e = {'a': d}
d['a'] = e
Run Code Online (Sandbox Code Playgroud)

那么我们就不能简单地序列d,和序列化e作为其一部分e。我们必须保持跟踪d已经序列化的状态,因为e否则序列化会导致序列化d等,直到耗尽内存为止。

因此,Pickle是存储Python对象的特定协议。但是我们不能使用它来序列化为特定格式,以便其他(非Python)程序可以读取它。