Python 对象序列化和反序列化:第 2 部分
这是有关序列化和反序列化 Python 对象的教程的第二部分。在第一部分中,您学习了基础知识,然后深入研究了 Pickle 和 JSON 的细节。
在这一部分中,您将探索 YAML(确保拥有第一部分中的运行示例),讨论性能和安全注意事项,了解其他序列化格式,最后了解如何选择正确的方案。 p>
YAML
YAML 是我最喜欢的格式。它是一种人性化的数据序列化格式。与 Pickle 和 JSON 不同,它不是 Python 标准库的一部分,因此您需要安装它:
pip 安装 yaml
yaml模块只有load()
和dump()
函数。默认情况下,它们使用像 loads()
和 dumps()
这样的字符串,但可以采用第二个参数,它是一个开放流,然后可以转储/加载到/来自文件。
import yaml print yaml.dump(simple) boolean: true int_list: [1, 2, 3] none: null number: 3.44 text: string
请注意 YAML 与 Pickle 甚至 JSON 相比的可读性。现在是 YAML 最酷的部分:它理解 Python 对象!无需自定义编码器和解码器。以下是使用 YAML 的复杂序列化/反序列化:
> serialized = yaml.dump(complex) > print serialized a: !!python/object:__main__.A simple: boolean: true int_list: [1, 2, 3] none: null number: 3.44 text: string when: 2016-03-07 00:00:00 > deserialized = yaml.load(serialized) > deserialized == complex True
如您所见,YAML 有自己的符号来标记 Python 对象。输出仍然非常容易阅读。日期时间对象不需要任何特殊标记,因为 YAML 本质上支持日期时间对象。
性能
在开始考虑性能之前,您需要考虑性能是否是一个问题。如果您相对不频繁地序列化/反序列化少量数据(例如在程序开始时读取配置文件),那么性能并不是真正的问题,您可以继续前进。
但是,假设您分析了系统并发现序列化和/或反序列化导致性能问题,则需要解决以下问题。
性能有两个方面:序列化/反序列化的速度有多快,以及序列化表示有多大?
为了测试各种序列化格式的性能,我将创建一个较大的数据结构,并使用 Pickle、YAML 和 JSON 对其进行序列化/反序列化。 big_data
列表包含 5,000 个复杂对象。
big_data = [dict(a=simple, when=datetime.now().replace(microsecond=0)) for i in range(5000)]
泡菜
我将在这里使用 IPython,因为它有方便的 %timeit
魔术函数来测量执行时间。
import cPickle as pickle In [190]: %timeit serialized = pickle.dumps(big_data) 10 loops, best of 3: 51 ms per loop In [191]: %timeit deserialized = pickle.loads(serialized) 10 loops, best of 3: 24.2 ms per loop In [192]: deserialized == big_data Out[192]: True In [193]: len(serialized) Out[193]: 747328
默认pickle需要83.1毫秒进行序列化,29.2毫秒进行反序列化,序列化大小为747,328字节。
让我们尝试使用最高协议。
In [195]: %timeit serialized = pickle.dumps(big_data, protocol=pickle.HIGHEST_PROTOCOL) 10 loops, best of 3: 21.2 ms per loop In [196]: %timeit deserialized = pickle.loads(serialized) 10 loops, best of 3: 25.2 ms per loop In [197]: len(serialized) Out[197]: 394350
有趣的结果。序列化时间缩短至仅 21.2 毫秒,但反序列化时间略有增加,达到 25.2 毫秒。序列化大小显着缩小至 394,350 字节 (52%)。
JSON
In [253] %timeit serialized = json.dumps(big_data, cls=CustomEncoder) 10 loops, best of 3: 34.7 ms per loop In [253] %timeit deserialized = json.loads(serialized, object_hook=decode_object) 10 loops, best of 3: 148 ms per loop In [255]: len(serialized) Out[255]: 730000
好的。编码方面的性能似乎比 Pickle 差一点,但解码方面的性能却差很多很多:慢了 6 倍。这是怎么回事?这是 object_hook
函数的一个工件,需要为每个字典运行以检查是否需要将其转换为对象。不使用对象挂钩运行速度要快得多。
%timeit deserialized = json.loads(serialized) 10 loops, best of 3: 36.2 ms per loop
这里的教训是,在序列化和反序列化为 JSON 时,请仔细考虑任何自定义编码,因为它们可能会对整体性能产生重大影响。
YAML
In [293]: %timeit serialized = yaml.dump(big_data) 1 loops, best of 3: 1.22 s per loop In[294]: %timeit deserialized = yaml.load(serialized) 1 loops, best of 3: 2.03 s per loop In [295]: len(serialized) Out[295]: 200091
好的。 YAML 真的非常非常慢。但是,请注意一些有趣的事情:序列化大小仅为 200,091 字节。比 Pickle 和 JSON 都好得多。让我们快速了解一下内部:
In [300]: print serialized[:211] - a: &id001 boolean: true int_list: [1, 2, 3] none: null number: 3.44 text: string when: 2016-03-13 00:11:44 - a: *id001 when: 2016-03-13 00:11:44 - a: *id001 when: 2016-03-13 00:11:44
YAML 在这里非常聪明。它确定所有 5,000 个字典共享相同的“a”键值,因此它仅存储一次并使用 *id001
为所有对象引用它。
安全
安全性通常是一个关键问题。 Pickle和YAML由于构造Python对象,很容易受到代码执行攻击。格式巧妙的文件可以包含将由 Pickle 或 YAML 执行的任意代码。无需惊慌。这是设计使然,并记录在 Pickle 的文档中:
警告:pickle 模块并非旨在防止错误或恶意构建的数据。切勿取消从不受信任或未经身份验证的来源收到的数据。
以及 YAML 文档中的内容:
警告:使用从不受信任的来源收到的任何数据调用 yaml.load 是不安全的! yaml.load 与 pickle.load 一样强大,因此可以调用任何 Python 函数。
您只需要了解,不应使用 Pickle 或 YAML 加载从不受信任的来源收到的序列化数据。 JSON 没问题,但是如果您有自定义编码器/解码器,那么您也可能会暴露。
yaml 模块提供了 yaml.safe_load()
函数,该函数仅加载简单的对象,但随后您会失去很多 YAML 的功能,并且可能选择只使用 JSON。
其他格式
还有许多其他可用的序列化格式。以下是其中的一些。
协议缓冲区
Protobuf(即协议缓冲区)是 Google 的数据交换格式。它是用 C++ 实现的,但具有 Python 绑定。它具有复杂的架构并有效地打包数据。非常强大,但不太容易使用。
消息包
MessagePack 是另一种流行的序列化格式。它也是二进制且高效的,但与 Protobuf 不同的是它不需要模式。它有一个类似于 JSON 的类型系统,但更丰富一些。键可以是任何类型,不仅支持字符串和非 UTF8 字符串。
CBOR
CBOR 代表简洁二进制对象表示。同样,它支持 JSON 数据模型。 CBOR 不像 Protobuf 或 MessagePack 那样出名,但它很有趣,原因有两个:
- 它是官方互联网标准:RFC 7049。
- 它专为物联网 (IoT) 设计。
如何选择?
这是一个大问题。这么多选择,你如何选择?让我们考虑一下应该考虑的各种因素:
- 序列化格式应该是人类可读和/或人类可编辑的吗?
- 是否会从不受信任的来源接收序列化内容?
- 序列化/反序列化是性能瓶颈吗?
- 序列化数据是否需要与非Python环境交换?
我会让您变得非常简单,并介绍几种常见场景以及我为每种场景推荐的格式:
自动保存Python程序的本地状态
此处使用 pickle (cPickle) 和 HIGHEST_PROTOCOL
。它快速、高效,无需任何特殊代码即可存储和加载大多数 Python 对象。它也可以用作本地持久缓存。
配置文件
绝对是 YAML。对于人类需要阅读或编辑的任何内容来说,没有什么比它的简单性更好的了。它已被 Ansible 和许多其他项目成功使用。在某些情况下,您可能更喜欢使用直接的 Python 模块作为配置文件。这可能是正确的选择,但它不是序列化,它实际上是程序的一部分,而不是单独的配置文件。
Web API
JSON 显然是这里的赢家。如今,Web API 最常由原生使用 JSON 的 JavaScript Web 应用程序使用。某些 Web API 可能会返回其他格式(例如,用于密集表格结果集的 csv),但我认为您可以以最小的开销将 csv 数据打包为 JSON(无需将每一行作为具有所有列名称的对象重复)。
高容量/低延迟大规模通信
使用二进制协议之一:Protobuf(如果需要架构)、MessagePack 或 CBOR。运行您自己的测试来验证每个选项的性能和代表能力。
结论
Python对象的序列化和反序列化是分布式系统的一个重要方面。您不能直接通过网络发送 Python 对象。您经常需要与用其他语言实现的其他系统进行互操作,有时您只想将程序的状态存储在持久存储中。
Python 在其标准库中附带了多种序列化方案,还有更多序列化方案可作为第三方模块使用。了解所有选项以及每个选项的优缺点将使您能够选择最适合您情况的方法。
以上是Python 对象序列化和反序列化:第 2 部分的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

本教程演示如何使用Python处理Zipf定律这一统计概念,并展示Python在处理该定律时读取和排序大型文本文件的效率。 您可能想知道Zipf分布这个术语是什么意思。要理解这个术语,我们首先需要定义Zipf定律。别担心,我会尽量简化说明。 Zipf定律 Zipf定律简单来说就是:在一个大型自然语言语料库中,最频繁出现的词的出现频率大约是第二频繁词的两倍,是第三频繁词的三倍,是第四频繁词的四倍,以此类推。 让我们来看一个例子。如果您查看美国英语的Brown语料库,您会注意到最频繁出现的词是“th

本文解释了如何使用美丽的汤库来解析html。 它详细介绍了常见方法,例如find(),find_all(),select()和get_text(),以用于数据提取,处理不同的HTML结构和错误以及替代方案(SEL)

处理嘈杂的图像是一个常见的问题,尤其是手机或低分辨率摄像头照片。 本教程使用OpenCV探索Python中的图像过滤技术来解决此问题。 图像过滤:功能强大的工具 图像过滤器

PDF 文件因其跨平台兼容性而广受欢迎,内容和布局在不同操作系统、阅读设备和软件上保持一致。然而,与 Python 处理纯文本文件不同,PDF 文件是二进制文件,结构更复杂,包含字体、颜色和图像等元素。 幸运的是,借助 Python 的外部模块,处理 PDF 文件并非难事。本文将使用 PyPDF2 模块演示如何打开 PDF 文件、打印页面和提取文本。关于 PDF 文件的创建和编辑,请参考我的另一篇教程。 准备工作 核心在于使用外部模块 PyPDF2。首先,使用 pip 安装它: pip 是 P

本教程演示了如何利用Redis缓存以提高Python应用程序的性能,特别是在Django框架内。 我们将介绍REDIS安装,Django配置和性能比较,以突出显示BENE

本文比较了Tensorflow和Pytorch的深度学习。 它详细介绍了所涉及的步骤:数据准备,模型构建,培训,评估和部署。 框架之间的关键差异,特别是关于计算刻度的

Python是数据科学和处理的最爱,为高性能计算提供了丰富的生态系统。但是,Python中的并行编程提出了独特的挑战。本教程探讨了这些挑战,重点是全球解释

本教程演示了在Python 3中创建自定义管道数据结构,利用类和操作员超载以增强功能。 管道的灵活性在于它能够将一系列函数应用于数据集的能力,GE
