首页 > 解决方案 > 关于反序列化一些数字的问题(错误??)

问题描述

为了反序列化 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错误?

任何答案将不胜感激。

标签: pythonnumpypickle

解决方案


pickle.loads的输入并不完全限制为一个bytes对象。引用文档

返回对象的腌制表示数据的重构对象层次结构。data必须是类似字节的对象

并引用“bytes-like object”文档

支持缓冲区协议并可以导出 C 连续缓冲区的对象。

缓冲区协议是对象将其底层内存缓冲区暴露给其他代码的一种方式,对于有意义的对象。NumPy 数组支持缓冲区协议,允许其他代码对数组的底层存储进行操作,而不是通过昂贵的 Python 级索引操作和包装对象。NumPy 标量也支持缓冲区协议,以尽可能无缝地处理 0 维数据。


错误pickle.loads(np.float64(0.34103))不是因为np.float64(0.34103)不是字节。如果你试图传入一个普通的float,你会得到一个 TypeError 因为类型是无效的(floats 不是字节状的),但是np.float64(0.34103)你得到的错误是因为pickle.loads试图读取缓冲区np.float64(0.34103)并发现数据没有有效的泡菜。

使用np.float64(0.34104),缓冲区的内容恰好是一个有效的泡菜侥幸的是,这些字节恰好匹配一个 NEWTRUE 操作码、一个 STOP 操作码和被忽略的尾随垃圾。NEWTRUE 将 True 压入pickle堆栈,STOP 停止 pickle 执行,并返回 True。


推荐阅读