【问题标题】:Error when loading a Python 2 .npy file in Python 3在 Python 3 中加载 Python 2 .npy 文件时出错
【发布时间】:2017-06-16 23:20:08
【问题描述】:

我有使用 Python 2.7.9 和 Numpy 版本 1.11.3 使用命令 np.save('filename') 创建的 .npy 文件。这些文件是在我们研究所 linux-cluster 的一部分的外部机器上生成的。我将文件复制到本地计算机,以便通过np.load('filename.npy') 导入它们。在我的本地机器上,我使用 Jupyter-Notebook 运行 Python 3.5.2 和 Numpy 版本 1.13.0。本地操作系统为 Ubuntu 16.04.2。

当我尝试在本地加载文件时出现错误:

ValueError: invalid literal for int() with base 16

在浏览了一些 Stackoverflow 问题后,我尝试指定编码:

np.load('filename.npy',encoding='latin1')

这给出了同样的错误。 encoding='bytes' 产量:

TypeError: can't multiply sequence by non-int of type 'float'

这是 Traceback 的更大的 sn-p:

/usr/local/lib/python3.5/dist-packages/numpy/lib/npyio.py in load(file, mmap_mode, allow_pickle, fix_imports, encoding)
417             else:
418                 return format.read_array(fid, allow_pickle=allow_pickle,
--> 419                                          pickle_kwargs=pickle_kwargs)
420         else:
421             # Try a pickle

/usr/local/lib/python3.5/dist-packages/numpy/lib/format.py in read_array(fp, allow_pickle, pickle_kwargs)
638             pickle_kwargs = {}
639         try:
--> 640             array = pickle.load(fp, **pickle_kwargs)
641         except UnicodeError as err:
642             if sys.version_info[0] >= 3:

/usr/local/lib/python3.5/dist-packages/sympy/core/numbers.py in __new__(cls, num, prec)
823                 else:
824                     _mpf_ = mpmath.mpf(
--> 825                         S.NegativeOne**num[0]*num[1]*2**num[2])._mpf_
826         elif isinstance(num, Float):
827             _mpf_ = num._mpf_

TypeError: can't multiply sequence by non-int of type 'float'

我猜在 Python 和 Numpy 版本之间的转换中编码出现了问题。关于如何导入文件的任何想法?

【问题讨论】:

  • 你不能在 Python 3 中加载 Python 2 Numpy 字节码,反之亦然,尝试没有任何意义。您是否尝试过在 python 2 中加载 .npy 文件?因为如果你使用的是 ubuntu,你已经安装了 python 2
  • 一般情况下不可能吗?我想我之前确实在 Python 3 中导入了 Python 2 .npy 文件,一切都很顺利。我无法确定为什么它之前没有导致错误……在 Python 2 中加载文件是可行的。 (我在笔记本单元格的开头插入%%python2 这样做)。但是使用 Python 2 会导致更多错误,因此我一直在寻找一种解决方案来坚持使用 Python 3 来使用这些文件。
  • 你知道这个文件里有什么吗?只是一个数字数组?或某种object。错误在pickle_load,提示后者。 np.save docs 对酸洗对象时的 PY2/3 兼容性有一些注意事项。
  • 这是一个重要的提示,谢谢!这些文件基本上只是二维数值数组。但是,存储到这些数组中的数值属于sympy.core.numbers.Float 类型。使用 NumPy 保存和加载会生成一个带有 dtype=object 的数组。我想我的问题的正确解决方法是在将 SymPy-Number 写入列表之前将其转换为 Python-Float。 @cat 也感谢您的解释!

标签: python numpy


【解决方案1】:

What is the way data is stored in *.npy? 所示,.npy 文件是字节码,如果你在十六进制编辑器中打开一个你会看到。

Python 2 字节码 .pyc.pyo 文件无法在 Python 3 中运行,因为虚拟机和编译器内部结构已随主要版本发生变化。

同样,NumPy 的 C 内部结构和字节码编译器在 Python 3 中也发生了变化,破坏了向后兼容性。 (这是故意的,因为字节码并不意味着要持续这么长时间,或者在与创建时不同的版本中使用。)

这些更改的组成意味着,如果不对 Python 3 的字节码解释器和 Python 3 的 NumPy 和/或从 Python 2 NumPy 字节码到 Python 3 的字节码的转译器进行巨大更改,就无法使用这些 Python 2 。 Python 3 中的 npy 文件。


正如我之前提到的,这有点像X/Y Problem。您不应该依赖 .npy 文件来跨版本工作,因为不能保证它们会起作用,因为它们本质上是一种易失格式(如 Python VM 字节码)。

不要对字节码进行逆向工程来调试它,而是尝试获取生成这些文件的源代码。

【讨论】:

  • 但是.npy 文件没有保存 Python 字节码或任何已编译的代码。它正在保存数据 - 数组属性加上数组数据缓冲区。 Py2和Py3之间pickling时存在不兼容,但数值数组不应该不同。
  • @hpaulj 不,但是二进制格式在版本 2 和 3 之间发生了变化,没有人应该(一直)依赖它来保持不变。就像为 Linux 2.6 编译的 ELF 二进制文件不会在 Linux 4.15 上运行一样,但该二进制文件几乎不包含编译器的任何内部结构(_start 等除外),ELF 解释器 ld.so 无法对您的旧版本进行正面或反面二进制文件,因此 Python 3 无法生成 Python 2 pycnpy 文件的首尾。
  • 顺便说一句,不能保证 CPython PyObject 内存布局不会在 2 和 3 之间改变,也不能保证 Numpy 的 C 对象内存布局和序列化不会在 2 和 3 之间改变 - - 它可能确实提高了主要版本的性能。
猜你喜欢
  • 2014-07-29
  • 1970-01-01
  • 2016-10-16
  • 2021-11-04
  • 1970-01-01
  • 2020-11-17
  • 2019-01-18
  • 2018-10-21
  • 1970-01-01
相关资源
最近更新 更多