加载一个pickle文件是否导入对象所在的模块?

3

我的理解是,从pickle中加载一个非内置类型的对象时,会导入该模块。例如, pickle无法导入已存在的模块?表明要解析的对象类型对应的模块必须存在于同一路径下。

然而,当我尝试反序列化一个NumPy的ndarray时,反序列化成功了,但是似乎没有导入模块:

In [12]: with open('numpysample.pkl', 'rb') as input:
    ...:     a = pickle.load(input)

In [14]: type(a)
Out[14]: numpy.ndarray

In [13]: numpy
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-13-8d40275025d1> in <module>
----> 1 numpy

NameError: name 'numpy' is not defined

这里正在发生什么?

1个回答

5
腌菜(Pickle)导入了这个模块,但不是到该命名空间。在pickle.load调用之前sys.modules中'numpy'将返回假,在调用之后将返回真。
“numpy是否没有被导入到任何名称空间中?”可以从pickle.Unpickler.find_class的源代码中得到答案。
    def find_class(self, module, name):
        # Subclasses may override this
        __import__(module)
        mod = sys.modules[module]
        klass = getattr(mod, name)
        return klass

在这个方法中,module参数指定的模块将在此函数作用域内绑定到mod变量。

1
请注意,在加载 pickle 文件后,导入 numpy 会非常快,因为它不会再次导入 numpy,而是只是从 sys.modules 中获取缓存的导入。 - ShadowRanger
谢谢;我尝试了 sys.modules,确实如你所说。我理解 pickle 导入了 numpy,但是可以这样说没有命名空间导入 numpy 吗?我这么说是因为没有将模块绑定到名称(仅在 sys.modules 字典中作为值引用)。 - rishai
这让我清楚了。由于__import __()不绑定要加载的模块的名称,而且在外部无法访问mod,因此没有一个名称可以用来直接引用未选择对象的类/模块。但是我想我们也可以从dir()globals()中知道这一点。 - rishai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接