Python 关于反序列化某些数字的问题(错误??)
为了反序列化bytes对象,我们使用pickle.loads() 预期结果如下所示(因为np.float64(0.34103)不是bytes对象,所以预期会出现适当的错误) 仅当转换的字节以b'\x88开头时(例如0.04263、0.08526、0.11651…)才会发生此情况 有人能回答这个问题是否是Python bug吗Python 关于反序列化某些数字的问题(错误??),python,numpy,pickle,Python,Numpy,Pickle,为了反序列化bytes对象,我们使用pickle.loads() 预期结果如下所示(因为np.float64(0.34103)不是bytes对象,所以预期会出现适当的错误) 仅当转换的字节以b'\x88开头时(例如0.04263、0.08526、0.11651…)才会发生此情况 有人能回答这个问题是否是Python bug吗 任何答案都将不胜感激。这不是Python错误pickle.loads可与any一起使用,numpy float就是其中之一。 从一开始,字节就是这样工作的:字节表示没有类型
任何答案都将不胜感激。这不是Python错误<代码>pickle.loads可与any一起使用,numpy float就是其中之一。
从一开始,字节就是这样工作的:字节表示没有类型的原始数据。表示numpy float
0.34104
的8个字节恰好与表示Python pickleTrue
的8个字节匹配,这纯粹是巧合
对于特定的pickle协议2,b'\x88.\xa8o\x99\xd3\xd5?
恰好是True
、pickle结束和被忽略的尾部垃圾的操作码
pickletools.dis(b'\x88.\xa8o\x99\xd3\xd5?)
0:\x88新路
1: . 停止
例如,“numpy float
0.34104
”的字节模式也匹配小端无符号/有符号Python整数4599815250385579656
、大端无符号Python整数9812965835362522431
、大端有符号Python整数-8633778238347029185
,拉丁文字符串'\x88.¨o\x99ÓÕ?'
和许多其他值
>int.from_字节(np.float64(0.34103),byteorder='big',signed=False)
13915064561919317311
pickle.load
的输入不限于字节
对象。引用
返回对象的pickle表示数据的重构对象层次结构。数据必须是有效的
并引用“类似字节的对象”
支持并可以导出C连续缓冲区的对象
缓冲区协议是对象向其他代码公开其底层内存缓冲区的一种方式,适用于有意义的对象。NumPy数组支持缓冲区协议,允许其他代码在数组的底层存储上操作,而无需执行昂贵的Python级索引操作和包装对象。NumPy标量也支持缓冲协议,以尽可能无缝地处理0维数据
pickle.loads(np.float64(0.34103))的错误不是因为
np.float64(0.34103)
不是字节。如果您试图传入一个普通的float
,您会得到一个类型错误,因为该类型无效(float
s与字节不同),但是对于np.float64(0.34103)
,您得到的错误是因为pickle.loads
尝试读取np.float64(0.34103)的缓冲区
并发现其中的数据不是有效的pickle
对于
np.float64(0.34104)
,缓冲区的内容恰好是一个有效的pickle。侥幸的是,字节恰好匹配一个NEWTRUE操作码、一个STOP操作码和被忽略的尾部垃圾。NEWTRUE在pickle
堆栈上推送一个True,停止pickle执行,返回True。将tobytes
与np.frombuffer
配对,将pickle.dumps
与pickle.loads配对。您尝试的配对没有意义。我在您的代码示例中没有看到tobytes
。我的意思是“np.float64(0.34104)。tobytes()”为我们提供了以b'x88开头的二进制表达式。此数字打印为真,而不是错误。有人能解释这种现象吗?为什么要尝试pickle.load(x)
其中x
不是pickle字节字符串?该协议并不是为接收这种随机数据而设计的。Python通常不是这样处理字节的。这里有特定的NumPy功能与pickle.load进行交互。大多数对象永远不会被这样解释。您的说法是,之所以会发生这种情况,是因为“字节就是这样工作的:字节是没有类型的原始数据。”,但Python不会将字节
视为“没有类型的原始数据”,而且它不会将任意对象的内存表示形式重新解释为字节。如果您尝试将大多数对象传递给pickle.loads
,它将立即引发类型错误,而不会尝试执行任何类型的字节解释。您的答案立即跳转到(错误的)关于pickle协议和numpy.float64(0.34104)
内存布局的断言,甚至没有考虑pickle.loads
将此对象视为有效输入的原因。这一点以及pickle.loads
像对象一样使用字节的事实。我对这个问题的解释是,最重要的一点是为什么pickle
甚至接受不是bytes
实例的对象-这个问题表达了一种期望,即非bytes
输入会引发错误。我很高兴我们能够澄清这一点。(错误的断言是字节与“表示Python pickle True的8字节”匹配的断言,好像只有一个pickle解pickle到True
,而这8个字节与该pickle匹配。您的编辑也修复了此问题。)
import pickle
import numpy as np
pickle.loads(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'.
pickle.loads(np.float64(0.34104))
True
np.float64(0.34104).tobytes()
b'\x88.\xa8o\x99\xd3\xd5?'