繁体   English   中英

带有莳萝的模块中的 Pickle 类定义

[英]Pickle class definition in module with dill

我的模块包含一个应该是pickleable的类,实例和定义我都有以下结构:

MyModule
|-Submodule
  |-MyClass

在关于 SO 的其他问题中,我已经发现 dill 能够腌制类定义,当然它可以通过将MyClass的定义复制到一个单独的脚本中并在那里腌制它来工作,就像这样:

import dill as pickle

class MyClass(object):
    ...

instance = MyClass(...)
with open(..., 'wb') as file:
   pickle.dump(instance, file)

但是,在导入类时它不起作用:

酸洗:

from MyModule.Submodule import MyClass
import dill as pickle

instance = MyClass(...)
with open(.., 'wb') as file:
    pickle.dump(instance, file)

加载:

import dill as pickle

with open(..., 'rb') as file:
    instance = pickle.load(file)

>>> ModuleNotFoundError: No module named 'MyModule'

我认为类定义是通过引用保存的,尽管它不应该具有 dill 中的默认设置。 MyClass被称为__main__.MyClass ,这是正确完成的,当在主脚本中定义类时会发生这种情况。

我想知道,有没有办法将MyClassMyModule分离出来? 有什么方法可以让它像顶级导入( __main__.MyClass )一样,所以 dill 知道如何将它加载到我的另一台机器上?

相关问题: 为什么 dill 无论如何都要通过引用转储外部类

我是dill作者。 这是您在上面提到的问题的副本。 相关的 GitHub 功能请求是: https : //github.com/uqfoundation/dill/issues/128

我认为更大的问题是您想要腌制另一个未安装的文件中定义的对象。 我相信这是目前不可能的。

作为一种解决方法,我相信您可以通过提取类(或模块)的源代码并动态进行酸洗,或者提取源代码并在__main__编译新对象来使用dill.source进行酸洗。

我设法使用以下脏技巧保存了我的类的实例和定义:

class MyClass(object):
    def save(path):
        import __main__

        with open(__file__) as f:
            code = compile(f.read(), "somefile.py", 'exec')
            globals = __main__.__dict__
            locals = {'instance': self, 'savepath': path}
            exec(code, globals, locals)

if __name__ == '__main__':
    # Script is loaded in top level, MyClass is now available under the qualname '__main__.MyClass'
    import dill as pickle

    # copy the attributes of the 'MyModule.Submodule.MyClass' instance to a bew 'MyClass' instance.
    new_instance = MyClass.__new__(MyClass)
    new_instance.__dict__ = locals()['instance'].__dict__

    with open(locals()['savepath'], 'wb') as f:       
        pickle.dump(new_instance, f)

使用exec语句可以从__main__执行文件,因此类定义也将被保存。 在不使用保存功能的情况下,不应将此脚本作为主脚本执行。

Dill 确实只在__main__存储对象的定义,而不是在模块中存储对象的定义,所以解决这个问题的一种方法是在 main 中重新定义这些对象:

def mainify(obj):
    import __main__
    import inspect
    import ast

    s = inspect.getsource(obj)
    m = ast.parse(s)
    co = compile(m, '<string>', 'exec')
    exec(co, __main__.__dict__)

进而:

from MyModule.Submodule import MyClass
import dill as pickle

mainify(MyClass)
instance = MyClass(...)
with open(.., 'wb') as file:
    pickle.dump(instance, file)

现在您应该能够从任何地方加载泡菜,即使MyModule.Submodule不可用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM