使用 python 3.8+(默认协议=5)时,pickle.load 在 python 3.7 中的(协议=4)对象上失败

Posted

技术标签:

【中文标题】使用 python 3.8+(默认协议=5)时,pickle.load 在 python 3.7 中的(协议=4)对象上失败【英文标题】:pickle.load fails on (protocol=4) objects from python 3.7 when using python 3.8+ (with default protocol=5) 【发布时间】:2021-07-16 19:55:51 【问题描述】:

Python 在 python 3.4 到 3.7 中将其 pickle 协议更改为 4,并在 python 3.8 中再次将其更改为 protocol=5。如何在 python 3.8 中打开旧的腌制文件?

我试过了:

>>> with open('data_frame_111.pkl','rb') as pfile:
...     x1 = pickle.load(pfile)
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: Can't get attribute 'new_block' on <module 
'pandas.core.internals.blocks' from '/opt/anaconda3/lib/python3.8/site- 
packages/pandas/core/internals/blocks.py'>

>>> with open('data_frame_111.pkl','rb') as pfile:
...     x1 = unpkl.load(pfile, protocol=4)

但是protocol 是pickle.dump 中的一个关键字,它不是pickle.load 的一部分。实例化 pickle.Unpickler() 也不起作用。但显然应该有办法。

在 python 3.7 中,我会 import pickle5 并使用它来打开较新的泡菜,但找不到在 python 3.8 中执行相反操作的文档。

【问题讨论】:

我认为问题不在于泡菜版本,而是pandas 版本。 pickle.load 没有 protocol 参数,因为自动检测到协议 所以无法在 python3.8 中使用pickleprotocol=4 加载腌制的熊猫数据框?看来得有办法了。虽然对象是一个数据框,但我没有在这里调用 pandas。 我会尝试将我的 pandas 版本升级到最新版本,看看是否能解决这个问题。还是说3.8环境下的新pandas版本不识别旧pandas版本的结构? 似乎是由0.23到0.24版本之间的pandas引起的。 github.com/Kaggle/docker-python/issues/519。我正在尝试使用 pandas v1.2.4 加载。 pickle 通过加载模块然后根据腌制数据重建类对象来工作。该错误表明您的熊猫没有所需的功能 pandas.core.internals.blocks,new_block。如果您在两台机器上都获得了 pandas 版本,您可能会发现源的 pandas 比目标的 pandas 更新。解决方法是更新熊猫。 【参考方案1】:

您需要升级到 pandas 的最新版本(1.3.1 对我有用)。或者,更准确地说,您执行pickle.dump(some_path) 时的pandas 版本应该与您执行pickle.load(some_path) 时的pandas 版本相同。

【讨论】:

这可能是正确的答案,但它带来了严重的设计缺陷。当您使用 pickle 存储数月或数年的数据时,如果检索数据的方法取决于当时使用的代码版本,那么它作为一种格式是不稳定的。 是的,我同意。 Pickle 文件不是长期存储的好选择。 使用 colab 时遇到此错误。修复是!pip install --upgrade pandas 这里有关于 python 3.7 到 3.8 泡菜 4 到 5 问题以及 pandas 1.2.x 到 1.3.x 与泡菜不兼容问题的更长解释:***.com/a/68939962/536538 --- I我仍在寻找修复。这是酸洗的重大突破性变化。【参考方案2】:
with open('data_frame_111.pkl','rb') as pfile:
    x1 = pickle.load(pfile)

尝试更改为:

import pandas as pd
with open('data_frame_111.pkl','rb') as pfile:
    x1 = pd.read_pickle(pfile)

由于安全漏洞问题,似乎发生了一些变化。

【讨论】:

我尝试了这两种方法,但都没有奏效,因为正如另一个答案所述,使用的熊猫版本会影响它是否有效。

以上是关于使用 python 3.8+(默认协议=5)时,pickle.load 在 python 3.7 中的(协议=4)对象上失败的主要内容,如果未能解决你的问题,请参考以下文章

AWS Elastic Beanstalk Python (3.8) 平台:除了使用 `requirements.txt` 之外,为带有 `--no-deps` 标志的 Python 包运行额外的 p

AWS Lambda在Python 3.8中不显示原因 异常堆栈跟踪

Python 3.8 新特性全面解读

在 Android 上的 kivymd 中使用 python 3.8 exchangelib 时出错

如何在Ubuntu 18.04上安装Python 3.8

Python 打印表格数据使用 Google 字体中断