如何加载一个旧的pickle文件?

3
我有一个旧的pickle文件,当我尝试加载它时,会出现错误。
ImportError: No module named oldname.submodule

这是因为oldname早已被改名为newname

我该如何加载此pickle文件?

我可以从oldname创建符号链接到newname,但我想知道是否有一种方法可以在不触及文件系统的情况下使模块oldname.*指向newname.*


即使使用符号链接也存在风险,因为如果您还导入了真实模块,则会有两个命名空间。如果模块使用全局状态,则可能会出现问题。也许您可以使用 sys.modules['oldname'] = sys.modules['newname'] - tdelaney
1个回答

1

不要使用符号链接来创建第二个并行模块和外部依赖项,而是在 sys.modules 中添加一个条目。为了测试,我对一个类实例进行了pickling,然后重命名了模块。

td@mintyfresh ~/tmp $ cat oldname.py
class Foo(object):
    def __init__(self):
        self.name = 'bar'

td@mintyfresh ~/tmp $ python
Python 2.7.6 (default, Oct 26 2016, 20:30:19) 
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import oldname
>>> foo = oldname.Foo()
>>> foo.name
'bar'
>>> import pickle
>>> pickle.dump(foo, open('test.pkl', 'wb'), 2)
>>> exit()
td@mintyfresh ~/tmp $ mv oldname.py newname.py
td@mintyfresh ~/tmp $ rm oldname.*

现在加载失败

td@mintyfresh ~/tmp $ python
Python 2.7.6 (default, Oct 26 2016, 20:30:19) 
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import newname
>>> import pickle
>>> foo = pickle.load(open('test.pkl', 'rb'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/pickle.py", line 1378, in load
    return Unpickler(file).load()
  File "/usr/lib/python2.7/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib/python2.7/pickle.py", line 1090, in load_global
    klass = self.find_class(module, name)
  File "/usr/lib/python2.7/pickle.py", line 1124, in find_class
    __import__(module)
ImportError: No module named oldname

但是如果我在sys.modules中复制该模块,它就可以工作。有趣的是,类实例具有新的模块名称。

>>> import sys
>>> sys.modules['oldname'] = sys.modules['newname']
>>> foo = pickle.load(open('test.pkl', 'rb'))
>>> foo
<newname.Foo object at 0x7f6b837d3310>

买方自负:如果类本身发生了很大的变化,腌菜(pickle)仍将失败。

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