Dill 无法在其他环境中反序列化

问题描述 投票:0回答:1

概述

我需要一个 Azure python 函数来提供 pickled 对象,并且我需要生成的 pkl 文件具有相当的可移植性,以便它可以在任何典型的笔记本或 python 代码文件中使用,只需最少的导入。

用于生成测试 pkl 文件字节的测试代码:

import dill

def test():
    print("It worked!")

result = dill.dumps(test)

结果手动保存到磁盘作为 pkl 文件。

用于在另一个项目中加载pkl文件的代码:

import dill
file = open('test.pkl', 'rb')
test = dill.load(file)
file.close()
test()

问题

在我的所有测试用例中,上述代码都有效,但是当运行代码从将部署到 Azure 的项目生成 pkl 文件时,生成的 pkl 文件无法加载到另一个项目(例如 jupyter 笔记本)中。

当我尝试加载 pkl 文件时,终端输出:

ModuleNotFoundError:没有名为“__app__”的模块

编辑:经过一番挖掘后发现 __app__ 模块是 Azure 函数的默认顶级模块。 此外,当尝试序列化函数和 lambda 时,dill 在输出中包含绝对路径,这似乎不对。 有谁知道解决方法? 我对这个领域不太熟悉,任何人都可以在这里提供的任何指示将不胜感激。

python azure-functions pickle dill
1个回答
4
投票

我是

dill
作者。
dill
假设相同的环境位于不同的资源上——这意味着安装了相同模块的相同版本。 如果上述情况不成立,它仍然可以工作,但不能保证。 这种情况并非
dill
所独有,因为否则pickle对象必须序列化所有依赖模块等。

但是您确实有一些选择。 当函数被序列化时,它可能还需要在

globals
中存储引用。您可以选择如何处理对
globals
中对象的引用。例如,
dill
中的默认值是将所有内容存储在
globals
中——因此,如果您的环境正在执行诸如在启动时将模块注入全局变量之类的操作...那么默认情况下,使用
dill
腌制的函数将假设 unpickle 时存在相同的模块。或者,您可以使用
globals
来限制函数从
dill.settings['recurse'] = True
存储的内容。 此设置将尝试将引用递归到
globals
中,并且仅在
globals
中存储具有对目标函数的指针引用的对象。

在这里您可以看到差异:

Python 3.7.12 (default, Nov 11 2021, 17:34:58) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> 
>>> def test():
...     print("It worked!")
... 
>>> result = dill.dumps(test)
>>> result
b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_create_code\nq\x01(K\x00K\x00K\x00K\x02KCC\x0ct\x00d\x01\x83\x01\x01\x00d\x00S\x00q\x02NX\n\x00\x00\x00It worked!q\x03\x86q\x04X\x05\x00\x00\x00printq\x05\x85q\x06)X\x07\x00\x00\x00<stdin>q\x07X\x04\x00\x00\x00testq\x08K\x01C\x02\x00\x01q\t))tq\nRq\x0bc__builtin__\n__main__\nh\x08NN}q\x0cNtq\rRq\x0e.'
>>> 
>>> dill.settings['recurse'] = True
>>> dill.dumps(test)
b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_create_code\nq\x01(K\x00K\x00K\x00K\x02KCC\x0ct\x00d\x01\x83\x01\x01\x00d\x00S\x00q\x02NX\n\x00\x00\x00It worked!q\x03\x86q\x04X\x05\x00\x00\x00printq\x05\x85q\x06)X\x07\x00\x00\x00<stdin>q\x07X\x04\x00\x00\x00testq\x08K\x01C\x02\x00\x01q\t))tq\nRq\x0b}q\x0cX\x05\x00\x00\x00printq\rcdill._dill\n_get_attr\nq\x0eX\x08\x00\x00\x00builtinsq\x0fX\x05\x00\x00\x00printq\x10\x86q\x11Rq\x12sh\x08NN}q\x13Ntq\x14Rq\x15.'

此外,当目标函数构建在文件中时,

dill
与全局字典的交互方式与
__main__
不同。 因此,您看到的结果将取决于您是在文件中还是在解释器中构建测试。

dill.settings
中还有其他序列化变体,其中
recurse
byref
与函数最相关。 仅当解释器中未定义该函数时,使用
dill.settings['byref'] = True
才会按名称引用存储该函数。

您还可以手动临时从全局字典中弹出有问题的条目,或者可以使用

exec
之类的东西创建一个新的全局字典,希望不包含有问题的条目。 我想如果更改设置对您不起作用,您可以尝试其中任何一个。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.