[英]Pickle class definition in module with dill
My module contains a class which should be pickleable, both instance and definition I have the following structure:我的模块包含一个应该是pickleable的类,实例和定义我都有以下结构:
MyModule
|-Submodule
|-MyClass
In other questions on SO I have already found that dill is able to pickle class definitions and surely enough it works by copying the definition of MyClass
into a separate script and pickling it there, like this:在关于 SO 的其他问题中,我已经发现 dill 能够腌制类定义,当然它可以通过将MyClass
的定义复制到一个单独的脚本中并在那里腌制它来工作,就像这样:
import dill as pickle
class MyClass(object):
...
instance = MyClass(...)
with open(..., 'wb') as file:
pickle.dump(instance, file)
However, it does not work when importing the class:但是,在导入类时它不起作用:
Pickling:酸洗:
from MyModule.Submodule import MyClass
import dill as pickle
instance = MyClass(...)
with open(.., 'wb') as file:
pickle.dump(instance, file)
Loading:加载:
import dill as pickle
with open(..., 'rb') as file:
instance = pickle.load(file)
>>> ModuleNotFoundError: No module named 'MyModule'
I think the class definition is saved by reference, although it should not have as per default settings in dill.我认为类定义是通过引用保存的,尽管它不应该具有 dill 中的默认设置。 This is done correctly when MyClass
is known as __main__.MyClass
, which happens when the class is defined in the main script.当MyClass
被称为__main__.MyClass
,这是正确完成的,当在主脚本中定义类时会发生这种情况。
I am wondering, is there any way to detach MyClass
from MyModule
?我想知道,有没有办法将MyClass
从MyModule
分离出来? Any way to make it act like a top level import ( __main__.MyClass
) so dill knows how to load it on my other machine?有什么方法可以让它像顶级导入( __main__.MyClass
)一样,所以 dill 知道如何将它加载到我的另一台机器上?
Relevant question: Why dill dumps external classes by reference no matter what相关问题: 为什么 dill 无论如何都要通过引用转储外部类
I'm the dill
author.我是dill
作者。 This is a duplicate of the question you refer to above.这是您在上面提到的问题的副本。 The relevant GitHub feature request is: https://github.com/uqfoundation/dill/issues/128 .相关的 GitHub 功能请求是: https : //github.com/uqfoundation/dill/issues/128 。
I think the larger issue is that you want to pickle an object defined in another file that is not installed.我认为更大的问题是您想要腌制另一个未安装的文件中定义的对象。 This is currently not possible, I believe.我相信这是目前不可能的。
As a workaround, I believe you may be able to pickle with dill.source
by extracting the source code of the class (or module) and pickling that dynamically, or extracting the source code and compiling a new object in __main__
.作为一种解决方法,我相信您可以通过提取类(或模块)的源代码并动态进行酸洗,或者提取源代码并在__main__
编译新对象来使用dill.source
进行酸洗。
I managed to save the instance and definition of my class using the following dirty hack:我设法使用以下脏技巧保存了我的类的实例和定义:
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)
Using the exec
statement the file can be executed from within __main__
, so the class definition will be saved as well.使用exec
语句可以从__main__
执行文件,因此类定义也将被保存。 This script should not be executed as main script without using the save function.在不使用保存功能的情况下,不应将此脚本作为主脚本执行。
Dill indeed only stores definitions of objects in __main__
, and not those in modules, so one way around this problem is to redefine those objects in 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__)
And then:进而:
from MyModule.Submodule import MyClass
import dill as pickle
mainify(MyClass)
instance = MyClass(...)
with open(.., 'wb') as file:
pickle.dump(instance, file)
Now you should be able to load the pickle from anywhere, even where the MyModule.Submodule
is not available.现在您应该能够从任何地方加载泡菜,即使MyModule.Submodule
不可用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.