Python3.8本地正常SSH服务器加载Pickle后报AttributeError:NoneType无axes属性
问题描述
我现在遇到一个奇怪的问题:我用Python 3.8写的代码在本地PC和SSH服务器上同时运行,其中一段从Pickle文件加载数据的函数在本地完全正常,但在服务器上出了问题。
我的加载函数代码如下:
from os.path import exists import _pickle as pickle def load_pickle(pickle_file): if exists(pickle_file): with open(pickle_file, 'rb') as f: loaded_dic = pickle.load(f) return loaded_dic else: return 'Pickle not found'
当pickle_file指向存在的文件时,函数应该返回一个字典;文件不存在则返回字符串'Pickle not found'。在本地PC上,这段代码能正常加载字典,后续访问字典里的内容也没问题。但在SSH服务器上,明明文件是存在的(我确认过路径正确),但尝试访问loaded_dic里的元素时,却抛出了这个错误:
AttributeError: 'NoneType' object has no attribute 'axes'
这说明loaded_dic实际上是None,但按照逻辑它应该返回加载后的字典才对。有没有大佬能帮我分析下问题出在哪,怎么解决?
排查与解决方案
哦,这个问题我之前碰到过类似的情况!咱们一步步来拆解可能的原因:
1. 先确认服务器上的Pickle文件本身是否正常
虽然你说文件存在,但有可能文件在传输到服务器的过程中损坏了,或者当初保存的时候就存了None进去。你可以在服务器上单独跑一段测试代码验证:
# 服务器上单独执行这个脚本 import _pickle as pickle file_path = "你的pickle文件绝对路径" with open(file_path, 'rb') as f: data = pickle.load(f) print(f"加载出的数据类型: {type(data)}") print(f"加载出的数据内容: {data}")
如果这里打印出来的类型是NoneType,那说明文件本身就有问题,得重新上传正确的Pickle文件到服务器。
2. 检查文件路径是否真的正确(相对路径坑)
本地和服务器的工作目录大概率不一样!比如你本地运行代码时在/home/you/project目录下,用相对路径data/xxx.pkl没问题,但服务器上运行代码的目录可能是/root或者其他路径,这时候相对路径就指向了一个不存在的文件?不对,你说文件存在,但万一exists()判断有问题?
或者你可以在代码里打印出实际访问的绝对路径,确认是不是你想的那个文件:
import os pickle_file = "你传入的路径" print(f"实际访问的绝对路径: {os.path.abspath(pickle_file)}")
然后去服务器上检查这个路径下的文件是不是你要的那个。最好的习惯是始终用绝对路径指定文件位置,避免工作目录差异带来的坑。
3. 试试替换_pickle为标准pickle模块
_pickle是C实现的底层模块,虽然速度快,但有时候兼容性不如标准库的pickle(尤其是不同环境下)。你可以把代码里的import _pickle as pickle改成import pickle,然后再测试:
from os.path import exists import pickle # 替换成标准pickle模块 def load_pickle(pickle_file): if exists(pickle_file): with open(pickle_file, 'rb') as f: loaded_dic = pickle.load(f) return loaded_dic else: return 'Pickle not found'
有时候这个小改动就能解决兼容性问题。
4. 检查文件的读取权限
服务器上运行代码的用户可能没有读取这个Pickle文件的权限!你可以在服务器终端里用ls -l查看文件权限:
ls -l 你的pickle文件路径
如果文件权限里没有r(读取)权限,比如显示-w-------,那Python进程就读不了这个文件。这时候可以用chmod修改权限:
chmod +r 你的pickle文件路径
给文件加上读取权限。
5. 确认函数返回值没被后续代码覆盖
有没有可能你调用load_pickle之后,loaded_dic被其他代码不小心改成None了?比如:
loaded_dic = load_pickle(pickle_file) # 中间有一段代码不小心把loaded_dic赋值为None loaded_dic = some_function_that_returns_None()
你可以在调用函数后立刻打印返回值的类型和内容,确认是不是函数本身返回了None:
loaded_dic = load_pickle(pickle_file) print(f"load_pickle返回值类型: {type(loaded_dic)}") print(f"load_pickle返回值内容: {loaded_dic}")
这样就能排除是不是后续代码搞的鬼。
内容的提问来源于stack exchange,提问作者Á. Garzón

