导入部分SciPy模块覆盖自定义警告过滤器问题求助
问题根源解释
你对Python警告过滤器的运行机制存在误解,核心和过滤器的版本绑定逻辑有关:
once过滤器的“仅触发一次”规则不是全局永久生效的,它的已警告记录会和当前的过滤器列表版本号绑定。- 只要有任何代码调用
warnings.simplefilter/filterwarnings/resetwarnings修改全局过滤器列表,就会触发版本号更新,之前所有once/module类过滤器的已警告记录会直接作废,等同于需要重新计数。哪怕SciPy设置的过滤器和你的自定义警告类完全无关,只要修改了全局过滤器列表,就会触发版本号更新,不需要过滤器匹配到你的警告。
SciPy的special、sparse模块在导入时,为了抑制自身的弃用警告,会主动修改全局警告过滤器列表,这就是导入后自定义警告被重新触发的原因。
无需重写过滤器的解决方案
方案1:调整导入顺序
把所有第三方库的导入操作,放在你设置自定义警告过滤器之前执行。让SciPy等库的过滤器修改操作,在你的自定义规则生效前完成,后续没有其他修改过滤器的操作,版本号就不会再变动,once的记录会一直有效。
修改后的示例代码:
import warnings # 先完成所有第三方库导入,让它们的过滤器配置先生效 from scipy import interpolate class W(DeprecationWarning): pass warnings.simplefilter("once", W) warnings.warn('warning!', W) warnings.warn('warning!', W) # 后续同类警告不会再触发 warnings.warn('warning!', W)
方案2:用上下文管理器包裹第三方库导入
如果无法调整导入顺序,可以用warnings.catch_warnings()包裹SciPy的导入操作。该上下文管理器会在进入时保存当前的过滤器状态,退出时完全恢复,SciPy在导入过程中对过滤器的所有修改只会在上下文内生效,不会影响外部的过滤器版本和已警告记录。
示例代码:
import warnings class W(DeprecationWarning): pass warnings.simplefilter("once", W) warnings.warn('warning!', W) warnings.warn('warning!', W) # 仅在上下文内允许SciPy修改过滤器 with warnings.catch_warnings(): from scipy import interpolate # 后续同类警告不会再触发 warnings.warn('warning!', W)
内容的提问来源于stack exchange,提问作者KCharlie
相关产品推荐
相关产品推荐

