Python出现FutureWarning与SettingWithCopyWarning如何定位触发代码
问题解答
是否由版本过旧导致
是,你当前使用的依赖版本普遍已经停止维护,两个警告均和版本过旧有直接关系:
- matplotlib 3.3.4是适配Python3.6的最高版本,该版本的内部cbook模块处理非numpy数组的多维索引时未做兼容转换,是已知的官方遗留问题,3.4及以上版本已经修复了该内部触发的警告
- pandas 1.1.5的SettingWithCopyWarning检测逻辑精度较低,存在更高的误触发概率,同时该版本对切片拷贝的校验规则比新版本更严格,更容易触发警告,本质是代码中存在对DataFrame切片直接赋值的操作。
定位触发警告的具体代码块
你可以通过以下方法快速定位:
- 开启警告转异常,打印全栈调用信息
在项目入口文件的最开头加入以下代码,所有警告会直接转为异常抛出,中断运行的同时打印完整调用栈,调用栈中属于你业务代码的行就是警告触发位置:import warnings # 所有警告转异常 warnings.filterwarnings('error') # 如果只想针对特定警告转异常,用下面的写法 # 针对matplotlib的FutureWarning # warnings.filterwarnings('error', category=FutureWarning) # 针对pandas的SettingWithCopyWarning # import pandas as pd # warnings.filterwarnings('error', category=pd.errors.SettingWithCopyWarning) - 分模块运行缩小范围
代码库规模较大时,可以按功能模块拆分运行,每次验证一个功能模块的运行输出,逐步缩小范围到具体的文件、函数。 - 配合调试工具定位
在入口文件加入import pdb; pdb.pm(),当警告转为异常抛出后会自动进入调试模式,输入where命令即可查看完整调用链路,逐层定位到业务代码的触发点。
警告修复方案
定位到具体代码后可以按以下规则修复:
- 针对matplotlib的FutureWarning
如果是业务代码中直接写了obj[:, None]这类非numpy数组的多维索引写法,提前将对象转为numpy数组即可:np.array(obj)[:, None];如果是给matplotlib绘图接口传了pandas的Series/Index对象触发的内部警告,传参时先转成numpy数组:plt.plot(df['列名'].values)代替plt.plot(df['列名']) - 针对pandas的SettingWithCopyWarning
如果需要修改原DataFrame的数值,统一用.loc语法赋值:df.loc[行筛选条件, 列名] = 新值;如果是需要基于切片生成独立的新DataFrame,显式调用copy方法:new_df = df[df['age']>18].copy(),后续修改new_df就不会触发警告。
内容的提问来源于stack exchange,提问作者Sarvendra Singh
相关产品推荐
相关产品推荐

