Python pickle加载自定义NaiveBayesSentiment类报AttributeError咨询
报错根因
pickle序列化不会把自定义类的源码打包进pkl文件,只会在序列化时记录类的完整引用路径。当初生成模型时,NaiveBayesSentiment类是定义在序列化脚本的__main__模块下,因此pkl文件内记录的类查找路径为__main__.NaiveBayesSentiment。
现在加载时报错,本质是执行pickle.load的瞬间,Python解释器还没在当前运行的__main__模块下定位到名为NaiveBayesSentiment的可用类,三类常见触发场景:
- 代码执行顺序颠倒:把模型加载逻辑写在了类定义的前面,加载时类还没被解释器加载进内存
- 类的作用域不对:类没有定义在模块的全局作用域下,被嵌在了其他函数/判断块里
- Flask Debug模式的热重载机制打乱了模块引用路径:开启
debug=True时,内置的reloader会重新加载主模块,导致pickle记录的路径和实际模块路径不匹配
具体修复操作
- 调整代码执行顺序
把NaiveBayesSentiment类的定义移到全局作用域最顶部,确保在执行pickle.load之前,类已经被解释器完成加载。同时清理原方法内的无效死代码:cleansing_data方法中return语句之后的两行代码永远不会被执行,属于之前写测试逻辑残留的冗余内容,直接删除即可。
正确的代码顺序参考:# 1. 优先导入所有依赖 import pickle import pandas as pd from flask import Flask # 2. 全局作用域定义NaiveBayesSentiment类,放在加载逻辑之前 class NaiveBayesSentiment(): def __init__(self, datasentimen, stopword, norm, datatest): self.datasentimen = datasentimen self.stop_word = stopword.T.values self.norm_words = pd.Series( norm['kata kbbi'].values, index=norm['kata singkatan'] ).to_dict() self.datatest = pd.DataFrame([datatest], columns=['comment']) def cleansing_data(self, datasentimen): datasentimen = datasentimen.replace('\n', ' ', regex=True) datasentimen = datasentimen.str.replace("[^a-zA-Z]+", " ", regex=True) datasentimen = datasentimen.str.replace('\s{2}', ' ', regex=True) datasentimen = datasentimen.str.lower() return datasentimen # 3. 初始化Flask应用实例 app = Flask(__name__) # 4. 类定义完成后再加载序列化模型 nb_model = pickle.load(open('model_pickle.pkl', 'rb')) - 排查热重载带来的路径偏移问题
按上述顺序调整代码后,如果仍偶发找不到类的报错,临时关闭Flask的debug模式和内置reloader验证:
如果需要保留开发阶段的热重载能力,可以把NaiveBayesSentiment类抽到独立的工具模块(比如if __name__ == "__main__": # 关闭热重载,避免模块路径被打乱 app.run(debug=False, use_reloader=False)nb_model.py),在app.py中导入类的同时,把类绑定到__main__模块的全局命名空间,匹配pkl内记录的类查找路径:import sys from nb_model import NaiveBayesSentiment # 将导入的类绑定到__main__全局空间,匹配pkl记录的路径 sys.modules['__main__'].NaiveBayesSentiment = NaiveBayesSentiment - 校验类定义一致性
确保当前app.py里的NaiveBayesSentiment类定义,和当初生成pkl文件时的类结构完全一致,包括类名、__init__方法的参数顺序、类属性的定义逻辑,不能随意增删方法或修改参数,否则即使能找到类,加载后的实例也会因为属性缺失触发其他报错。
内容的提问来源于stack exchange,提问作者Pheat Lie
相关产品推荐
相关产品推荐

