首页 > 解决方案 > 有没有办法腌制对象,以便在单独运行中检索它们

问题描述

我想知道是否有可能在不提供 MyClass 代码的情况下以某种方式正确读取泡菜文件。

import pickle


class MyClass:
    def __init__(self, n):
        self._n = n

    def give_vec(self):
        return [1 for _ in range(self._n)]


if __name__ == '__main__':
    m = MyClass(30)

    with open('test.pickle', 'wb') as p:
        pickle.dump(m, p)

假设我们已经运行了上面的代码,现在启动一个 python 解释器并尝试以下操作

>>> import pickle
>>> p = open('test.pickle', 'rb')
>>> a = pickle.load(p)

这样我们就不会收到此错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Can't get attribute 'MyClass' on <module '__main__' (built-in)>

这个想法是提供一个有一些接口而不指定确切类的泡菜

标签: pythonpython-3.xserializationpickle

解决方案


不幸的是,仅靠泡菜是不可能的。

来自https://docs.python.org/3/library/pickle.html#pickle-picklable

函数的代码和它的任何函数属性都不会被腌制。因此,定义模块必须在 unpickling 环境中是可导入的,并且模块必须包含命名对象,否则将引发异常。

所以只能腌制数据,而不是关联类的行为。

但是你可以使用dill

dill 可用于将 python 对象存储到文件中,但主要用途是将 python 对象作为字节流通过网络发送。dill 非常灵活,允许序列化任意用户定义的类和函数。

只需替换import pickleimport dill as pickle,它将起作用:

import dill as pickle


class MyClass:
    def __init__(self, n):
        self._n = n

    def give_vec(self):
        return [1 for _ in range(self._n)]


if __name__ == '__main__':
    m = MyClass(30)

    with open('test.pickle', 'wb') as p:
        pickle.dump(m, p)
>>> import dill as pickle
>>> p = open('test.pickle', 'rb')
>>> a = pickle.load(p)
>>> a
<__main__.MyClass object at 0x7eff33758340>

推荐阅读