Python pickling after changing a module's directory
我最近改变了程序的目录布局:之前,我把所有模块放在"main"文件夹中。现在,我已将它们移动到以程序命名的目录中,并在其中放置
现在我在我的主目录中有一个.py文件,用于启动我的程序,这个文件更整洁。
无论如何,尝试加载以前版本的程序中的pickle文件是失败的。我得到了,"ImportError:没有模块命名工具" - 我想这是因为我的模块以前在主文件夹中,现在它在whyteboard.tools中,而不仅仅是简单的工具。但是,在工具模块中导入的代码与它位于同一目录中,因此我怀疑是否需要指定包。
所以,我的程序目录看起来像这样:
<5233>
whyteboard.py从whyteboard / gui.py启动一个代码块,启动GUI。在目录重新组织之前,肯定没有发生这种酸洗问题。
正如pickle的文档所说,为了保存和恢复类实例(实际上也是一个函数),你必须尊重某些约束:
pickle can save and restore class
instances transparently, however the
class definition must be importable
and live in the same module as when
the object was stored
如果您的pickle文件是良好/高级格式(与旧的ascii格式相反,仅出于兼容性原因而默认),一旦执行此类更改,迁移它们实际上可能不像"编辑文件"那么简单(这是二元&amp; c ......!),尽管另一个答案表明。我建议你做一个"pickle-migrating script":让它像这样补丁
1 2 3 4 | import sys from whyteboard import tools sys.modules['tools'] = tools |
然后
发生在我身上,通过在加载pickle之前将模块的新位置添加到sys.path来解决它:
1 2 3 4 | import sys sys.path.append('path/to/whiteboard') f = open("pickled_file","rb") pickle.load(f) |
这可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import io import pickle class RenameUnpickler(pickle.Unpickler): def find_class(self, module, name): renamed_module = module if module =="tools": renamed_module ="whyteboard.tools" return super(RenameUnpickler, self).find_class(renamed_module, name) def renamed_load(file_obj): return RenameUnpickler(file_obj).load() def renamed_loads(pickled_bytes): file_obj = io.BytesIO(pickled_bytes) return renamed_load(file_obj) |
然后你需要使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type"help","copyright","credits" or"license" for more information. >>> import dill >>> >>> class Foo(object): ... def bar(self): ... return 5 ... >>> f = Foo() >>> >>> _f = dill.dumps(f) >>> >>> class Foo(object): ... def bar(self, x): ... return x ... >>> g = Foo() >>> f_ = dill.loads(_f) >>> f_.bar() 5 >>> g.bar(4) 4 |
这是pickle的正常行为,unpickled对象需要将其定义模块导入。
您应该能够通过编辑pickle文件来更改模块路径(即从