Pickle 对于 numpy.void 对象仍然失败

map*_*apf 12 python numpy pickle pycharm

一年多前,我报告了在腌制一些相当复杂的数据时遇到的一个错误。当时我不知道问题是什么,并认为它可能与递归引用有关。

我在处理项目时多次遇到这个问题,但只做了任意的事情来尝试修复它,直到错误消失。现在我终于花时间找出问题的根源并完善我的 MWE。这就是我想出的:

import pickle
import numpy as np


# create data
dtypes = [('f0', 'O')]
# for some reason, I need at least an extra of 19 fields for it to crash
# immediately
dtypes += [(f'f{i+1}', 'i4') for i in range(19)]
data = np.empty(1, dtype=dtypes)
# print(data[0])

# dump data
dump = pickle.dumps(data[0], pickle.HIGHEST_PROTOCOL)
# print('dumping works')

# load data
load = pickle.loads(dump)
# print('loading works')

# process crashes here if len(dtypes) > 19
print(load)

# process prints random data, e.g.

# (((...), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 0, 0,
# -1931060898, 32763, 1472326776, 503, 1482667496, 503, 0, 0, 1484270024,
# 503, 1472326776, 503, -1930803631, 32763, 1484270024, 503)

# or

# ((((((...), False, True), False, True), dtype('int32'), None), 0, 0), 0, 0)

# or

# (((...), <cell at 0x0000017018A25888: str object at 0x000001701AF998F0>,
# <cell at 0x0000017019084498: bool object at 0x00007FFB8D0EA970>,
# <cell at 0x00000170190842B8: int object at 0x00007FFB8D16A270>,
# <cell at 0x000001701927E2E8: str object at 0x0000017018989BB0>,
# <cell at 0x0000017018A3E798: bool object at 0x00007FFB8D0EA970>),
# 0, 0, -1931060898, 32763, 451341512)

# and crashes immediately afterwards if 2 <= len(dtypes) <= 19.

# process finishes with exit code 0 if data has no additional fields except f0,
# and prints 

# (((...),),)
Run Code Online (Sandbox Code Playgroud)

现在我知道过去也报告过类似的问题:

用于多处理的酸洗/取消酸洗 numpy.void 和 numpy.record

numpy.void 和 pickle 的分段错误

Python - numpy.void 对象的酸洗失败

在最近的一个非常相似的案例中

加载 pickled void 对象后出现段错误

似乎已经引入了修复程序,但是我的代码仍然导致崩溃:

Process finished with exit code -1073741819 (0xC0000005)
Run Code Online (Sandbox Code Playgroud)

现在对于Python - pickling 失败了 numpy.void 对象,接受的答案是jottos的评论(2009 年 12 月 29 日 18:42):

因此,pickling 仅适用于顶级模块函数和类,并且不会 pickle 类数据,因此,如果需要某些 numpy 类代码/数据来生成 numpy void 类型的表示,pickling 将无法按预期工作。numpy 包可能已经实现了一个内部 repr 将 void 类型打印为元组,如果是这种情况,那么您腌制的内容肯定不会是您打印的内容。

但这是十多年前的事了,似乎从那时起就引入了错误修复。那么这仍然是这里正在发生的事情,还是有别的原因?特别是因为我的代码显示出如此任意的行为。

设置信息

Windows:10 Home,v.21H1,内部版本 19043.1288

PyCharm:2021.2(专业版),内部版本 #PY-212.4746.96

Python(通过 anaconda):3.7.7 [MSC v.1916 64 位(AMD64)]

麻木:1.19.2

泡菜:4.0