从dill pickle文件提取源代码报OSError: could not extract source code如何解决
报错原因
dill.source.getsource 是对Python内置inspect.getsource的封装,它仅从当前运行环境的源码文件、交互式会话历史中查找目标对象的源代码,不会从pickle序列化文件内读取内容。你跨会话加载dill序列化的实例时,当前运行环境没有对应类的源码定义,因此触发提取失败报错。
另外注意不要直接把pickle文件路径传入getsource,该接口仅支持接收Python对象作为入参,不支持直接解析序列化文件。
实现方案
方案1:序列化阶段同步存储类源码
如果需要从序列化文件中直接读取源码,在序列化时就把类的源码和实例绑定存储即可:
import dill class Foo(object): def bar(self, x): return self.y + x def __init__(self, y): self.y = y # 序列化 f = Foo(5) save_pkg = { "instance": f, "foo_source": dill.source.getsource(Foo) } with open('foo_with_source.pkl', 'wb') as pkl: dill.dump(save_pkg, pkl) # 反序列化直接读取源码 with open('foo_with_source.pkl', 'rb') as pkl: load_pkg = dill.load(pkl) print(load_pkg["foo_source"])
方案2:使用dill内置源码序列化接口
dill提供了dumpsource/loadsource专门用于序列化类/函数的源码,无需手动拼接存储逻辑:
import dill class Foo(object): def bar(self, x): return self.y + x def __init__(self, y): self.y = y # 序列化类源码 with open('foo_source.pkl', 'wb') as pkl: dill.dumpsource(Foo, pkl) # 跨会话加载得到可直接运行的类 with open('foo_source.pkl', 'rb') as pkl: LoadedFoo = dill.loadsource(pkl) # 正常使用类,也可直接提取源码 print(dill.source.getsource(LoadedFoo)) f = LoadedFoo(5) print(f.bar(3))
方案3:序列化时强制按值存储类定义
如果需要保留实例的运行状态,同时支持加载后提取源码,序列化时开启by_value=True参数,让dill把类的完整定义(而非仅类引用路径)写入序列化文件:
import dill class Foo(object): def bar(self, x): return self.y + x def __init__(self, y): self.y = y f = Foo(5) # 序列化时开启by_value=True with open('foo_full.pkl', 'wb') as pkl: dill.dump(f, pkl, by_value=True) # 跨会话加载 with open('foo_full.pkl', 'rb') as pkl: b = dill.load(pkl) # 此时可正常提取类源码 print(dill.source.getsource(b.__class__))
内容的提问来源于stack exchange,提问作者sakeesh
相关产品推荐
相关产品推荐

