warnings警告控制

源代码: Lib / warnings.py


警告消息通常在有用的情况下发出,提醒用户程序中的某些情况,那个条件(通常)不值得提出异常并终止程序。例如,当程序使用过时的模块时,可能会发出警告.

Python程序员通过调用此模块中定义的warn()函数来发出警告。(C程序员使用PyErr_WarnEx();请参阅异常处理了解详情).

警告信息通常写入sys.stderr,但是他们的处置可以灵活地改变,从忽略所有警告到将它们变成例外。警告的处理方式可能因警告类别(见下文),警告消息的文本以及警告消息的来源位置而异。对同一源位置的特定警告的重复通常会被抑制.

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

是否发出警告消息的确定由警告过滤器控制,警告过滤器是一系列匹配规则和操作。通过调用filterwarnings()可以将规则添加到过滤器中并通过调用resetwarnings().

重置为其默认状态。通过调用showwarning()来打印警告消息,可以覆盖它;此函数的默认实现通过调用formatwarning()格式化themessage,也可以由自定义实现使用.

参见

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

警告类别

有许多代表警告类别的内置异常。这种分类对于过滤掉警告组很有用.

虽然这些在技术上是内置的例外,但它们在这里被记录,因为从概念上讲它们属于警告机制.

用户代码可以通过继承其中一个标准警告类别来定义其他警告类别。警告类别必须始终是Warning class的子类.

当前定义了以下警告类别类:

描述
Warning 这是所有warningcategory类的基类。它是Exception.
UserWarning 默认类别warn().
DeprecationWarning 当这些警告针对其他Python开发人员时,有关deprecatedfeatures警告的基本类别(默认情况下被忽略,除非由__main__).
SyntaxWarning 关于dubioussyntactic功能警告的基本类别.
RuntimeWarning 关于可疑时间特征警告的基本类别.
FutureWarning 有关deprecatedfeatures的警告的基本类别,当这些警告用于预防用于编写在Java中的应用程序的用户时
PendingDeprecationWarning 关于将来不推荐使用的功能的警告的基本类别(默认情况下被忽略).
ImportWarning 导入模块过程中触发警告的基本类别(默认忽略).
UnicodeWarning 与Unicode相关警告的基本类别
BytesWarning bytesbytearray.
ResourceWarning 与资源使用有关的警告的基本类别.

更改版本3.7:以前DeprecationWarningFutureWarning根据功能是否被完全删除或改变其行为来进行区分。它们现在根据其目标受众以及默认警告过滤器处理它们的方式进行区分.

警告过滤器

警告过滤器控制警告是否被忽略,显示或转入错误(引发异常).

从概念上讲,警告过滤器维护一个有序的过滤器规范列表;任何特定警告依次与列表中的每个过滤器规范匹配,直到找到匹配为止;过滤器确定匹配的处置。每个条目都是一个形式的元组(action,message, category, module, lineno),其中:

  • action是以下字符串之一:

    处理
    "default" 打印每个位置的第一次匹配警告(模块+行)号码)警告发出的地方
    "error" 将匹配警告转为例外
    "ignore" 永不打印匹配警告
    "always" 始终打印匹配警告
    "module" 打印发出警告的每个模块的第一次匹配警告(无论行号)
    "once" 仅打印第一次匹配警告,无论位置如何
  • message是包含警告消息的开头必须匹配的正则表达式的字符串。表达式被编译为永远不区分大小写

  • category是一个类(的子类Warning)其中,warningcategory必须是子类才能匹配.

  • module是一个包含模块名称必须匹配的正则表达式的字符串。表达式被编译为大小写敏感.

  • lineno是一个整数,表示发生警告的行号必须匹配,或0以匹配所有行号.

因为Warning class派生自内置的Exception类,将警告变为我们简单引发的错误category(message).

如果报告的警告与任何已注册的警告不匹配过滤然后应用“默认”操作(因此其名称).

描述警告过滤器

警告过滤器由-W初始化传递给Python解释器命令行的选项PYTHONWARNINGS环境变量。解释器在sys.warnoptions中保存所有提供的条目的参数而不解释;warnings模块在首次导入时解析这些(忽略无效选项后,将消息打印到sys.stderr)。

单个警告过滤器被指定为由字符串分隔的字段序列:

action:message:category:module:line

每个字段的含义如中所述//警告过滤。列出多个过滤器时在单行上(和PYTHONWARNINGS一样),各个过滤器用逗号分隔,后面列出的过滤器优先于前面列出的过滤器(从左到右应用,最近应用的过滤器)过滤器优先于早期的).​​

常用的警告过滤器适用于所有警告,特定类别的警告或特定模块或软件包引发的警告。一些示例:

default                      # Show all warnings (even those ignored by default)ignore                       # Ignore all warningserror                        # Convert all warnings to errorserror::ResourceWarning       # Treat ResourceWarning messages as errorsdefault::DeprecationWarning  # Show DeprecationWarning messagesignore,default:::mymodule    # Only report warnings triggered by "mymodule"error:::mymodule[.*]         # Convert warnings to errors in "mymodule"                             # and any subpackages of "mymodule"

默认警告过滤器

默认情况下,Python会安装几个警告过滤器,可以通过-W命令行选项覆盖,PYTHONWARNINGS环境变量并调用filterwarnings().

在常规版本中build,默认警告过滤器具有以下条目(按优先顺序排列):

default::DeprecationWarning:__main__ignore::DeprecationWarningignore::PendingDeprecationWarningignore::ImportWarningignore::ResourceWarning

在调试版本中,默认警告过滤器列表为空.

版本3.2:DeprecationWarning现在默认情况下被忽略除了PendingDeprecationWarning.

在版本3.7中更改:DeprecationWarning默认情况下,当__main__.

更改版本3.7:BytesWarning不再出现在默认过滤器列表中,并且不是通过sys.warnoptions什么时候 -b是指定的.

覆盖默认过滤器

用Python编写的应用程序的开发人员可能希望隐藏all默认情况下,来自用户的Python级别警告,仅在运行测试或在应用程序上运行时显示它们。sys.warnoptions用于将过滤器配置传递给解释器的attribute可用作标记来指示是否应禁用警告

import sysif not sys.warnoptions:    import warnings    warnings.simplefilter("ignore")

建议Python代码测试运行程序的开发人员确保所有警告默认显示在测试代码中,使用代码:

import sysif not sys.warnoptions:    import os, warnings    warnings.simplefilter("default") # Change the filter in this process    os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses

最后,交互式shell的开发人员在__main__建议确保DeprecationWarning默认情况下,使用以下代码(其中user_ns用于执行交互式输入代码的模块):

import warningswarnings.filterwarnings("default", category=DeprecationWarning,                                   module=user_ns.get("__name__"))

暂时禁止警告

如果您使用的代码会引发警告,例如不推荐使用的函数,但不希望看到警告(即使警告已通过命令行明确配置),则可以使用来警告警告。catch_warnings上下文管理员:

import warningsdef fxn():    warnings.warn("deprecated", DeprecationWarning)with warnings.catch_warnings():    warnings.simplefilter("ignore")    fxn()

上下文管理器中,所有警告都将被忽略。这允许您使用已知弃用的代码,而不必查看警告,同时不会抑制可能不知道其使用已弃用代码的其他代码的警告。注意:这只能在单线程应用程序中得到保证。如果两个或多个线程使用catch_warningscontextmanager同时,行为未定义.

测试警告

要测试代码引发的警告,请使用catch_warningscontextmanager。有了它,你可以暂时改变警告过滤器,以方便你的测试。例如,执行以下操作以捕获所有引发的警告tocheck:

import warningsdef 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)

通过使用error而不是always,还可以使所有警告成为例外。有一点需要注意的是,如果因为once/default规则,那么无论什么过滤器设置,除非警告注册表与警告有关,否则不会再次看到警告.

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

当测试多个引发相同类型警告的操作时,以一种方式测试它们很重要确认每个操作都会发出新的警告(例如,设置警告作为例外引发并检查操作是否引发异常,检查警告列表的长度是否在每次操作后继续增加,或者在每次新操作之前从警告列表中删除previousentries).

为新版本的依赖项更新代码

默认情况下忽略Python开发人员主要关注的警告类别(大多数是用Python编写的应用程序的最终用户).

值得注意的是,这个“默认忽略”列表包括DeprecationWarning(除了__main__),这意味着开发人员应该确保测试他们的代码,通常忽略警告,以便及时收到有关未来API更改的通知(无论是在标准库还是第三方软件包中).

在理想的情况下,代码将有一个合适的测试套件,测试运行器将在运行测试时隐式启用所有警告(由unittest模块这样做。)

在不太理想的情况下,可以通过传递-Wd到Python解释器(这是-W default)或设置PYTHONWARNINGS=default在环境中。这样可以对所有警告进行默认处理,包括默认情况下忽略的警告。要更改遇到警告的操作,您可以更改传递给-W(例如。-W error)。见-W有关可能的更多细节的旗帜.

可用功能

warnings.warnmessage, category=None, stacklevel=1, source=None

发出警告,或者忽略它或引发异常。category参数,如果给出,必须是警告类别类(见上文);它默认为UserWarning。或者message可以是Warning实例,在这种情况下category将被忽略并且message.__class__将被使用。在这种情况下,消息文本将是str(message)。如果通过警告过滤器将发出的特定警告更改为错误,此函数会引发异常,如上所述。stacklevel参数可以用Python编写的包装函数来使用,如下所示:

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

这使警告引用deprecation()的调用者,而不是deprecation()本身(因为后者会破坏警告信息的目的).

source,如果提供的话,是被破坏的物体,它发出了ResourceWarning.

改变版本3.6:添加source参数.

warnings.warn_explicit (message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None

这是warn(),明确地传递消息,类别,文件名和行号,以及可选的模块名称和注册表(应该是模块__warningregistry__字典)。模块名称默认为带有.py stripped的文件名;如果没有传递注册表,警告永远不会被抑制.message必须是一个字符串和category Warningmessage的子类可能是Warning实例,在这种情况下category将被签名.

module_globals,如果提供,应该是发出警告的代码使用的全局命名空间。(这个参数用于支持在zip文件或其他非文件系统导入源中找到的模块的displayingsource).

source,如果提供的话,是被破坏的对象,它发出一个ResourceWarning.

在版本3.6中更改:添加source参数

warnings.showwarning// (message, category, filename, lineno, file=None, line=None)

对文件发出警告。默认实现调用formatwarning(message, category, filename, lineno, line)并将结果字符串写入file默认sys.stderr。您可以通过分配给warnings.showwarning.line功能的低级接口,是一行包含在warningmessage中的源代码;如果没有提供lineshowwarning()willtry读取filenamelineno.

warnings.formatwarningmessage, category, filename, lineno, line=None)指定的行

用标准方式格式化警告。这将返回一个字符串,该字符串可能包含新行并以换行符结尾。line是包含在警告消息中的一行源代码;如果line不提供,formatwarning()将尝试读取filenamelineno.

warnings.filterwarningsaction, message=””, category=Warning, module=””, lineno=0, append=False

警告过滤器规格。默认情况下,条目插入前面;如果append为真,则在最后插入。这将检查参数的类型,编译messagemodule正则表达式,并将它们作为警告过滤器列表中的元组插入。如果两者都匹配特定警告,则靠近列表前面的条目会覆盖列表后面的条目。省略的参数默认为一个匹配任何东西的值.

warnings.simplefilteraction, category=Warning, lineno=0, append=False

警告过滤规范列表中插入一个简单的条目。函数参数的含义与filterwarnings(),但是不需要正则表达式,因为只要类别和行号匹配,filterinserted总是匹配任何模块中的任何消息.

warnings.resetwarnings ( )

重置警告过滤器。这会丢弃以前所有调用filterwarnings()的效果,包括-W命令行选项和调用simplefilter().

可用上下文管理器

class warnings.catch_warnings*, record=False, module=None

一个上下文管理器,它复制并在退出时恢复警告过滤器和showwarning()函数。如果record参数是False(默认值),则上下文管理器返回None进入时如果recordTrue,返回一个列表,逐渐填充对象,如自定义showwarning()函数所示(也禁止输出到sys.stdout)。列表中的每个对象都有与showwarning().

的参数同名的属性module参数采用一个模块来代替导入时返回的模块warnings其过滤器将受到保护。这个论点主要用于测试warnings模块本身.

注意

catch_warnings经理通过更换然后恢复模块的工作来工作showwarning()功能和过滤器规范的内部列表。这意味着上下文管理器正在修改全局状态,因此不是thread-safe。