python - 关于反序列化一些数字的问题(错误??)
问题描述
为了反序列化 bytes 对象,我们使用 pickle.loads()
import pickle
import numpy as np
pickle.loads(np.float64(0.34103))
并且预期的结果如下所示(因为 np.float64(0.34103) 不是字节对象,预计会出现适当的错误)
---------------------------------------------------------------------------
UnpicklingError Traceback (most recent call last)
<ipython-input-19-5c07606a60f1> in <module>
----> 1 pickle.loads(np.float64(0.34103))
UnpicklingError: invalid load key, '\xc1'.
这里我们有一些问题,一些数字(很少见)像 0.34104 打印以下结果而没有错误。
pickle.loads(np.float64(0.34104))
True
仅当转换的字节以 b'\x88 开头时才会发生这种情况(例如 0.04263、0.08526、0.11651 ...)
np.float64(0.34104).tobytes()
b'\x88.\xa8o\x99\xd3\xd5?'
谁能回答这个问题是否是Python错误?
任何答案将不胜感激。
解决方案
pickle.loads
的输入并不完全限制为一个bytes
对象。引用文档,
返回对象的腌制表示数据的重构对象层次结构。data必须是类似字节的对象。
并引用“bytes-like object”文档,
支持缓冲区协议并可以导出 C 连续缓冲区的对象。
缓冲区协议是对象将其底层内存缓冲区暴露给其他代码的一种方式,对于有意义的对象。NumPy 数组支持缓冲区协议,允许其他代码对数组的底层存储进行操作,而不是通过昂贵的 Python 级索引操作和包装对象。NumPy 标量也支持缓冲区协议,以尽可能无缝地处理 0 维数据。
错误pickle.loads(np.float64(0.34103))
不是因为np.float64(0.34103)
不是字节。如果你试图传入一个普通的float
,你会得到一个 TypeError 因为类型是无效的(float
s 不是字节状的),但是np.float64(0.34103)
你得到的错误是因为pickle.loads
试图读取缓冲区np.float64(0.34103)
并发现数据没有有效的泡菜。
使用np.float64(0.34104)
,缓冲区的内容恰好是一个有效的泡菜。侥幸的是,这些字节恰好匹配一个 NEWTRUE 操作码、一个 STOP 操作码和被忽略的尾随垃圾。NEWTRUE 将 True 压入pickle
堆栈,STOP 停止 pickle 执行,并返回 True。
推荐阅读
- scala - 错误:使用 Spark Structured Streaming 读取和写入数据到 kafka 中的另一个主题
- apache-kafka - 使用 Jmx Exporter for Prometheus 缺少 Kafka Connect 指标
- sparql - Wikidata/Wikidata-Toolkit 通过 SPARQL 查询获取实体 (#362)
- postgresql - 如何为 spring-boot-starter-data-jpa + PostgreSQL 时间戳指定 UTC 时区
- python - 如何通过 Python 中的 Sagemath 库理解可疑的语法应用程序
- javascript - 使用javascript根据滚动位置更改菜单项
- amazon-web-services - 如何将本地文件上传到 AWS 弹性文件系统 (EFS)
- zapier - 重置目标日期列值
- api - 使用 OpenId Connect 保护 API
- c# - 如何格式化字符串“1441/10/15”与 DateTime C# 完全相同?