28.6. 警告-警告控制

2.1 版中的新Function。

源代码: Lib/warnings.py


警告消息通常是在警告用户程序中某些情况的情况下发出的,该情况(通常)不保证引发异常并终止程序。例如,当程序使用过时的模块时,可能要发出警告。

Python 程序员pass调用此模块中定义的warn()函数发出警告。 (C 程序员使用PyErr_WarnEx();有关详细信息,请参见Exception Handling)。

通常将警告消息写入sys.stderr,但是可以灵活地更改警告消息的处理方式,从忽略所有警告到将其变为异常。根据警告类别(请参阅下文),警告消息的文本以及发出警告的源位置,警告的处理方式可能会有所不同。通常会禁止针对同一源位置重复发出特定警告。

警告控制分为两个阶段:首先,每次发出警告时,都会确定是否应发布消息;接下来,如果要发布消息,则使用用户可设置的钩子对消息进行格式化和打印。

是否发出警告消息的确定由警告过滤器控制,警告过滤器是一系列匹配的规则和动作。可以pass调用filterwarnings()将规则添加到过滤器,并pass调用resetwarnings()将规则重置为默认状态。

警告消息的打印是pass调用showwarning()来完成的,它可以被覆盖;此函数的默认实现pass调用formatwarning()来格式化消息,该信息也可用于自定义实现。

See also

logging.captureWarnings()允许您使用标准日志记录基础结构处理所有警告。

28.6.1. 警告类别

有许多内置的异常表示警告类别。这种分类对于能够过滤出警告组很有用。当前定义了以下警告类别类:

Class Description
Warning 这是所有警告类别类的 Base Class。它是Exception的子类。
UserWarning warn()的默认类别。
DeprecationWarning 有关不推荐使用的Function的警告的基本类别(默认情况下被忽略)。
SyntaxWarning 警告有关可疑语法Function的基本类别。
RuntimeWarning 有关可疑的运行时Function的警告的基本类别。
FutureWarning 用于警告将来会在语义上更改的结构的警告的基本类别。
PendingDeprecationWarning 有关将来将不推荐使用的Function的警告的基本类别(默认情况下被忽略)。
ImportWarning 导入模块过程中触发的警告的基本类别(默认情况下忽略)。
UnicodeWarning 与 Unicode 相关的警告的基本类别。
BytesWarning 与字节和字节数组有关的警告的基本类别。

尽管这些是技术上内置的异常,但在此处进行了记录,因为从概念上讲,它们属于警告机制。

用户代码可以pass将标准警告类别之一子类化来定义其他警告类别。警告类别必须始终是Warning类的子类。

在 2.7 版中进行了更改:默认情况下,DeprecationWarning被忽略。

28.6.2. 警告过滤器

警告过滤器控制警告是被忽略,显示还是变成错误(引发异常)。

从概念上讲,警告过滤器会维护过滤器规格的有序列表。依次将所有特定警告与列表中的每个过滤器规范进行匹配,直到找到匹配项为止;match 决定 match 的安排。每个条目都是以下形式的 Tuples(* action message category module lineno *),其中:

Value Disposition
"error" 将匹配的警告变为异常
"ignore" 从不打印匹配的警告
"always" 始终打印匹配的警告
"default" 在发出警告的每个位置打印匹配警告的第一次出现
"module" 为发出警告的每个模块打印第一次出现的匹配警告
"once" 无论位置如何,仅打印第一次出现的匹配警告

由于Warning类是从内置的Exception类派生的,因此要将警告变为错误,我们只需提高category(message)即可。

警告过滤器pass传递给 Python 解释器命令行的-W选项进行初始化。解释器将所有-W选项的参数保存,而不在sys.warnoptions中解释; warnings模块在首次导入时对其进行解析(将消息打印到sys.stderr之后,无效选项将被忽略)。

28.6.2.1. 默认警告过滤器

默认情况下,Python 安装几个警告过滤器,可以pass传递给-W的命令行选项和对filterwarnings()的调用来覆盖这些警告过滤器。

28.6.3. 暂时禁止警告

如果您使用的代码知道会发出警告(例如已弃用的函数),但又不想看到该警告,则可以使用catch_warnings上下文 Management 器来抑制该警告:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    fxn()

在上下文 Management 器中,所有警告都将被忽略。这使您可以使用已知已弃用的代码,而不必查看警告,而不必为可能不知道其已弃用代码的其他代码取消警告。注意:只能在单线程应用程序中保证这一点。如果两个或多个线程同时使用catch_warnings上下文 Management 器,则该行为是不确定的。

28.6.4. 测试警告

要测试代码引发的警告,请使用catch_warnings上下文 Management 器。有了它,您可以临时更改警告过滤器以方便您的测试。例如,执行以下操作以捕获所有引发的警告以进行检查:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

pass使用error而不是always,也可以使所有警告均为 exception。要注意的一件事是,如果由于once/default规则而已经发出警告,那么,除非设置了与该警告相关的警告注册表,否则无论设置了什么过滤器,都不会再次看到该警告。

上下文 Management 器退出后,警告过滤器将恢复为 Importing 上下文时的状态。这样可以防止测试在测试之间以意外方式更改警告过滤器,并导致不确定的测试结果。模块中的showwarning()Function也恢复为其原始值。注意:只能在单线程应用程序中保证这一点。如果两个或多个线程同时使用catch_warnings上下文 Management 器,则行为是不确定的。

当测试引发相同警告的多个操作时,以确认每个操作正在发出新警告的方式进行测试非常重要(例如,将警告设置为引发异常,并检查操作引发异常,并检查操作长度)每次操作后,警告列表的数量 continue 增加,或者在每次新操作之前,从警告列表中删除以前的条目)。

28.6.5. 为新版本的 Python 更新代码

默认情况下,仅会忽略开发人员感兴趣的警告。因此,您应该确保使用可见的通常被忽略的警告来测试代码。您可以pass在命令行中将-Wd传递给解释器来完成此操作(这是-W default的简写)。这将启用所有警告的默认处理,包括默认情况下会忽略的警告。要更改针对遇到的警告采取的措施,您只需更改将传递给-W的参数,例如-W error。有关可能的更多详细信息,请参见-W标志。

要pass编程方式与-Wd相同,请使用:

warnings.simplefilter('default')

确保尽快执行此代码。这样可以防止已发出警告的记录意外地影响将来的警告的处理方式。

默认情况下,某些警告会被忽略,以防止用户看到开发人员仅感兴趣的警告。由于您不一定控制用户使用什么解释器来运行其代码,因此有可能在您的发布周期之间发布新版本的 Python。新的解释器版本可能会在您的代码中触发旧的解释器中不存在的新警告,例如DeprecationWarning用于您正在使用的模块。当您作为开发人员希望收到有关您的代码正在使用不推荐使用的模块的通知时,对于用户而言,此信息本质上是噪音,对他们没有任何好处。

28.6.6. 可用Function

def deprecation(message):
    warnings.warn(message, DeprecationWarning, stacklevel=2)

这使警告指向deprecation()的调用者,而不是deprecation()本身的来源(因为后者会破坏警告消息的目的)。

在版本 2.5 中进行了更改:添加了* module_globals *参数。

2.6 版的新Function。

在 2.7 版中更改:必须支持* line *参数。

在 2.6 版中进行了更改:添加了* line *参数。

28.6.7. 可用的上下文 Management 器

Note

catch_warningsManagement 器的工作方式是替换并随后恢复模块的showwarning()Function和过滤器规格的内部列表。这意味着上下文 Management 器正在修改全局状态,因此不是线程安全的。

Note

在 Python 3 中,catch_warnings的构造函数参数是仅关键字参数。

2.6 版的新Function。

首页