Python 3.6加载pickle文件报错ModuleNotFoundError: No module named '__builtin__'解决方法
在使用Python 3.6加载旧版本(主要是Python 2.x)生成的pickle文件时,经常会出现ModuleNotFoundError: No module named '__builtin__'的错误。这个错误的核心原因是Python 2和Python 3的内置模块命名存在差异,pickle文件在序列化时记录了对应版本的内置模块路径,加载时无法匹配当前Python 3的环境导致报错。下面我们详细分析问题的成因,并提供对应的解决思路。
问题成因分析
Python 2的内置函数和异常类等对象都定义在__builtin__模块中,而Python 3中这个模块被重命名为builtins。当你用Python 3的pickle模块加载Python 2生成的pickle文件时,pickle会尝试导入__builtin__模块,但该模块在Python 3中不存在,因此就会抛出上述错误。
解决方案
方案一:自定义unpickler兼容旧模块路径
我们可以通过自定义pickle的Unpickler类,重写find_class方法,把pickle文件中引用的__builtin__模块映射到Python 3的builtins模块,从而解决模块找不到的问题。下面是完整的代码示例:
import pickle
import builtins
class CompatibleUnpickler(pickle.Unpickler):
def find_class(self, module, name):
# 如果是旧的__builtin__模块,替换为Python 3的builtins模块
if module == "__builtin__":
module = "builtins"
return super().find_class(module, name)
def load_pickle_file(file_path):
"""
加载pickle文件,兼容Python 2生成的pickle文件
:param file_path: pickle文件路径
:return: 加载后的数据
"""
with open(file_path, "rb") as f:
# 使用自定义的Unpickler加载文件
data = CompatibleUnpickler(f).load()
return data
if __name__ == "__main__":
# 示例:加载名为old_data.pkl的pickle文件
try:
result = load_pickle_file("old_data.pkl")
print("pickle文件加载成功,数据为:", result)
except Exception as e:
print("加载失败,错误信息:", e)上述代码中,我们定义了CompatibleUnpickler类继承pickle的Unpickler,在find_class方法中判断如果模块名是__builtin__,就替换为builtins,其余逻辑保持和原Unpickler一致。调用时直接使用这个自定义的Unpickler加载文件,就可以正常解析旧版本的pickle文件。
方案二:重新生成pickle文件(推荐长期使用)
如果条件允许,最好的方式是用Python 3重新生成一份pickle文件,避免后续的兼容性问题。可以用Python 3加载旧文件后再重新保存,代码如下:
import pickle
def migrate_pickle_file(old_path, new_path):
"""
将旧版本pickle文件迁移为Python 3兼容的版本
:param old_path: 旧pickle文件路径
:param new_path: 新pickle文件路径
"""
# 先使用兼容方式加载旧文件
with open(old_path, "rb") as f:
# 这里也可以用方案一中的自定义Unpickler,避免重复代码
import builtins
class TempUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == "__builtin__":
module = "builtins"
return super().find_class(module, name)
data = TempUnpickler(f).load()
# 用Python 3的pickle重新保存
with open(new_path, "wb") as f:
pickle.dump(data, f)
print(f"迁移完成,新文件保存为{new_path}")
if __name__ == "__main__":
migrate_pickle_file("old_data.pkl", "new_data.pkl")这样生成的新pickle文件是完全基于Python 3环境的,后续用标准pickle.load加载就不会再出现模块找不到的错误。
注意事项
- 如果pickle文件中包含Python 2特有的对象类型(比如旧版本的自定义类),即使替换了
__builtin__模块,也可能出现其他兼容性问题,这种情况需要额外处理对应类的映射。 - 加载未知来源的pickle文件存在安全风险,pickle可以执行任意代码,建议只加载自己生成的或者可信来源的pickle文件。
- 如果报错不是
__builtin__相关,而是其他模块找不到,可以参考方案一的思路,在find_class方法中添加对应的模块映射规则。
PythonpickleModuleNotFoundError兼容Python2迁移 本作品最后修改时间:2026-05-23 21:50:26