【python 内置模块】warnings

2024-01-20 00:00:00

目录:

warnings 模块介绍

warnings 模块是用于向用户发出非致命警报的重要工具,它允许程序在遇到某些不理想但又不至于引发异常并终止程序的情况时,向用户发出提示。

与异常不同,警告旨在提醒用户注意程序中的某些条件,例如使用了已过时的模块或存在可疑的语法,而程序本身可以继续执行。

这个模块为框架和库的开发者提供了一种优雅的方式来标记即将废弃的功能或潜在问题,是Python生态中不可或缺的调试与兼容性维护机制。

警告类别

所有警告类别都继承自 Exception 的子类 Warning,Python 内置了多种警告类别,以满足不同场景的需求。

  • UserWarning:warn() 函数的默认类别,适用于用户代码触发的通用警告;
  • DeprecationWarning:用于标记已废弃、未来可能被移除的功能,主要面向其他 Python 开发者。在默认过滤规则下,这类警告通常被忽略,除非是在__main__模块中直接触发的;
  • FutureWarning:同样用于标记未来会发生变更的功能,但主要面向使用 Python 编写的应用程序的最终用户;
  • SyntaxWarning、RuntimeWarning:分别用于提示可疑的语法和运行时行为;
  • ImportWarning、PendingDeprecationWarning、ResourceWarning 等:分别用于模块导入、即将废弃的功能和资源使用相关的警告,它们在默认情况下通常也被忽略;

用户可以通过继承这些内置类别来定义自己的警告类别,以实现更精细化的警告控制。

警告过滤器

警告过滤器是控制警告是否被显示、忽略或转为异常的核心机制。它维护着一个有序的规则列表,每条规则是一个包含动作(action)、消息匹配模式(message)、警告类别(category)、模块名(module)和行号(lineno)的元组。

当一个警告被触发时,它会依次与过滤器列表中的规则进行匹配,第一个匹配的规则将决定其最终命运。

动作(action)的可选值包括:

  • “ignore”:忽略匹配的警告;
  • “default”:为每个发出警告的位置(模块+行号)打印第一次出现的匹配警告;
  • “always”:总是打印匹配的警告;
  • “error”:将匹配的警告转换为异常;
  • “module”:为每个发出警告的模块打印第一次匹配警告;
  • “once”:无论位置如何,仅打印第一次出现的匹配警告;

主要函数

warnings.warn()

warnings.warn(message, category=None, stacklevel=1, source=None)

这是最常用的函数,用于触发一条警告。

  • category 参数默认为 UserWarning,你也可以传递一个 Warning 的子类来指定警告类型;
  • stacklevel 参数非常有用,它可以指定在调用栈中向上回溯的层数,从而让警告信息指向调用者而 非warn() 数本身,这在编写包装函数时尤其重要;

warnings.filterwarnings()

warnings.filterwarnings(action, message=’’, category=Warning, module=’’, lineno=0, append=False)

用于向警告过滤器列表中添加一条规则,提供了最精细的控制能力。

可以通过 message(正则表达式,不区分大小写)和 module(正则表达式,区分大小写)参数来匹配特定的警告文本或模块,从而实现高度定制化的过滤。

warnings.simplefilter()

warnings.simplefilter(action, category=Warning, lineno=0, append=False)

这是 filterwarnings() 的一个简化版本,它插入的过滤器会匹配任何模块中的任何消息,只要类别和行号匹配即可,使用起来更为便捷。

warnings.resetwarnings()

warnings.resetwarnings() 重置警告过滤器,清除所有通过 filterwarnings() 或 simplefilter() 添加的规则,以及命令行 -W 选项的效果,恢复到解释器的默认状态。

warnings.catch_warnings()

warnings.catch_warnings(record=False, module=None)

这是一个上下文管理器,用于在代码块内临时改变警告处理行为。

进入上下文管理器时,它会复制当前的警告过滤器和 showwarning() 函数,并在退出时恢复原状。当 record=True 时,它会返回一个列表,记录在上下文中触发的所有警告对象,这对于测试代码中触发的警告非常有用。

示例: 发出基本警告

import warnings

warnings.warn("这是一个用户警告信息")
# 默认会触发一个UserWarning

示例: 标记废弃函数并控制显示位置

import warnings

def deprecated_function():
    warnings.warn("此函数已废弃,请使用 new_function 替代", DeprecationWarning, stacklevel=2)
# 调用此函数时,警告信息会指向调用deprecated_function()的代码行,而非函数内部。

示例: 全局忽略特定类型警告

在数据分析或导入大量第三方库时,常会遇到不重要的 DeprecationWarning 或 FutureWarning,可以全局忽略它们以保持输出整洁。

import warnings

warnings.filterwarnings('ignore', category=DeprecationWarning)
warnings.filterwarnings('ignore', category=FutureWarning)

示例: 将警告转为异常

在开发或测试阶段,有时需要确保某些警告被严肃对待,可以将其提升为异常。

import warnings

warnings.simplefilter('error', category=DeprecationWarning) # 将 DeprecationWarning 转为异常
try:
    # 调用会触发DeprecationWarning的代码
    pass
except DeprecationWarning as e:
    print(f"捕获到废弃警告异常: {e}")

示例: 使用上下文管理器临时忽略警告

如果只想在特定代码段(如使用已知的废弃 API)中屏蔽警告,而不影响全局设置,可以使用上下文管理器。

import warnings

def using_old_api():
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        # 此代码块内触发的所有警告将被忽略
        # ... 调用旧API的代码 ...

示例: 测试代码是否触发了特定警告

使用 catch_warnings(record=True) 可以捕获并验证代码触发的警告,是单元测试中的常用技巧。

import warnings

def function_that_warns():
    warnings.warn("预期中的警告", UserWarning)

with warnings.catch_warnings(record=True) as w:
    warnings.simplefilter("always")
    function_that_warns()
    assert len(w) == 1
    assert issubclass(w[-1].category, UserWarning)
    assert "预期中的警告" in str(w[-1].message)

返回首页

本文总阅读量  次
皖ICP备17026209号-3
总访问量: 
总访客量: