【问题标题】:How to replace objects causing import errors with None during pickle load?如何在 pickle 加载期间用 None 替换导致导入错误的对象?
【发布时间】:2017-10-20 21:30:43
【问题描述】:

我有一个腌制结构,由嵌套的内置原语(列表、字典)和不再在项目中的类的实例组成,因此会在取消腌制期间导致错误。我并不真正关心这些对象,我希望我可以提取存储在这个嵌套结构中的数值。有什么方法可以从文件中提取并替换由于导入问题而损坏的所有内容,比如None

如果找不到类,我试图从Unpickler 继承并覆盖find_class(self, module, name) 以返回Dummy,但由于某种原因,之后我在load reduce 中不断收到TypeError: 'NoneType' object is not callable

class Dummy(object):
    def __init__(self, *argv, **kwargs):
        pass

我尝试了类似的东西

class RobustJoblibUnpickle(Unpickler):
    def find_class(self, _module, name):
        try:
            super(RobustJoblibUnpickle, self).find_class(_module, name)
        except ImportError:
            return Dummy

【问题讨论】:

  • 你是说你可以腌制一个对象但不能解开它?这里更广泛的任务是什么?
  • @roganjosh 该结构(列表的字典列表..)在不久前被腌制,此后代码库发生了显着变化;现在,如果我尝试解开它,我将面临导入错误,因为没有像那里使用的类,尽管我不需要存储在那里的对象,即使只有数值和字符串我也可以;所以,是的,广泛的问题是我无法解开它

标签: python pickle python-import built-in


【解决方案1】:

也许您可以在 try 块中捕获异常,然后做您想做的事情(将一些对象设置为 None 使用 Dummy 类)?

编辑:

看看这个,我不知道这样做是否正确,但它似乎工作正常:

import sys
import pickle

class Dummy:
    pass

class MyUnpickler(pickle._Unpickler):
    def find_class(self, module, name): # from the pickle module code but with a try
        # Subclasses may override this. # we are doing it right now...
        try:
            if self.proto < 3 and self.fix_imports:
                if (module, name) in _compat_pickle.NAME_MAPPING:
                    module, name = _compat_pickle.NAME_MAPPING[(module, name)]
                elif module in _compat_pickle.IMPORT_MAPPING:
                    module = _compat_pickle.IMPORT_MAPPING[module]
            __import__(module, level=0)
            if self.proto >= 4:
                return _getattribute(sys.modules[module], name)[0]
            else:
                return getattr(sys.modules[module], name)
        except AttributeError:
            return Dummy

# edit: as per Ben suggestion an even simpler subclass can be used
# instead of the above

class MyUnpickler2(pickle._Unpickler):
    def find_class(self, module, name):
        try:
            return super().find_class(module, name)
        except AttributeError:
            return Dummy

class C:
    pass

c1 = C()

with open('data1.dat', 'wb') as f:
    pickle.dump(c1,f)

del C # simulate the missing class

with open('data1.dat', 'rb') as f:
    unpickler = MyUnpickler(f) # or MyUnpickler2(f)
    c1 = unpickler.load()

print(c1) # got a Dummy object because of missing class

【讨论】:

  • 好吧,你需要以某种方式在 unpickle 例程“内部”执行此操作,以便在用 None 替换对象后继续 unpickling
  • 是的,我尝试过类似的方法,我的问题可能出在其他地方;如果我理解正确,使用 super().find_class(self, module, name)try .. catch 块内可以更轻松地完成。但我的问题似乎在其他地方。不过,感谢您指出这一点。
  • 很好的建议,为此 +1,并且刚刚改进了我的答案代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 2021-10-22
  • 2016-11-12
  • 1970-01-01
  • 2013-01-29
相关资源
最近更新 更多