Python 的 warnings 模块支持在代码运行中向用户输出警告,本文记录相关内容。
warnings 模块中定义的 warn()函数来发布警告。
sys.stderr,但可以灵活改变,从忽略所有警告到变成异常都可以。警告的处理方式可以依据警告类型 、警告信息的文本和发出警告的源位置而进行变化。同一源位置重复出现的警告通常会被抑制。
filterwarnings()可将规则加入过滤器,调用 resetwarnings()则可重置为默认状态。
showwarning() 完成的,该函数可被重写;默认的实现代码是调用 formatwarning()进行格式化,自己编写的代码也可以调用此格式化函数。
Warning类的子类。
类 | 描述 |
|---|---|
Warning | 这是所有警告类别的基类。它是 Exception 的子类。 |
UserWarning | The default category for warn() |
DeprecationWarning | 已废弃特性警告的基类,这些警告是为其他 Python 开发者准备的(默认会忽略,除非在 __main__ 中用代码触发)。 |
SyntaxWarning | 用于警告可疑语法的基类。 |
RuntimeWarning | 用于警告可疑运行时特性的基类。 |
FutureWarning | 用于警告已废弃特性的基类,这些警告是为 Python 应用程序的最终用户准备的。 |
PendingDeprecationWarning | 用于警告即将废弃功能的基类(默认忽略)。 |
ImportWarning | 导入模块时触发的警告的基类(默认忽略)。 |
UnicodeWarning | 用于 Unicode 相关警告的基类。 |
BytesWarning | bytes 和 bytearray 相关警告的基类。 |
ResourceWarning | 资源使用相关警告的基础类别(默认会被忽略)。ignored by default). |
在 3.7 版更改: 以前
DeprecationWarning和FutureWarning是根据某个功能是否完全删除或改变其行为来区分的。现在是根据受众和默认警告过滤器的处理方式来区分的。
警告过滤器控制着警告是否被忽略、显示或转为错误(触发异常)。
从概念上讲,警告过滤器维护着一个经过排序的过滤器类别列表;任何具体的警告都会依次与列表中的每种过滤器进行匹配,直到找到一个匹配项;过滤器决定了匹配项的处理方式。每个列表项均为 ( action , message , category , module , lineno ) 格式的元组,其中:
"default" 为发出警告的每个位置(模块+行号)打印第一个匹配警告 "error" 将匹配警告转换为异常 "ignore" 从不打印匹配的警告 "always" 总是打印匹配的警告 "module" 为发出警告的每个模块打印第一次匹配警告(无论行号如何) "once" 无论位置如何,仅打印第一次出现的匹配警告 -W 和 PYTHONWARNINGS中,message 是警告消息的开头需要包含的字符串字面值(对大小写不敏感),将忽略 message 开头和末尾的任何空格。
Warning 的子类),警告类别必须是其子类,才能匹配。
-W and PYTHONWARNINGS, module is a literal string that the fully qualified module name must be equal to (case-sensitively), ignoring any whitespace at the start or end of module.
0 表示与所有行号匹配。
如果警告不匹配所有已注册的过滤器,那就会应用 “default” 。
-W 选项和 PYTHONWARNINGS 环境变量初始化。解释器在 sys.warningoptions 中保存了所有给出的参数,但不作解释;warnings 模块在第一次导入时会解析这些参数(无效的选项被忽略,并会先向 sys.stderr 打印一条信息)。
1 | action:message:category:module:line |
|---|
PYTHONWARNINGS),过滤器间用逗号隔开,后面的优先于前面的(因为是从左到右应用的,最近应用的过滤器优先于前面的)。
1234567 | 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" |
|---|
-W命令行参数、 PYTHONWARNINGS环境变量及调用 filterwarnings()进行覆盖。
12345 | default::DeprecationWarning:__main__ignore::DeprecationWarningignore::PendingDeprecationWarningignore::ImportWarningignore::ResourceWarning |
|---|
sys.warningoptions 属性可以作为一个标记,表示是否应该禁用警告:12345 | import sysif not sys.warnoptions: import warnings warnings.simplefilter("ignore") |
|---|
建议 Python 代码测试的开发者使用如下代码,以确保被测代码默认显示 所有 警告:
123456 | import sysif not sys.warnoptions: import os, warnings warnings.simplefilter("default") # Change the filter in this process os.environ"PYTHONWARNINGS" = "default" # Also affect subprocesses |
|---|
最后,建议在 __main__ 以外的命名空间运行用户代码的交互式开发者,请确保 DeprecationWarning 在默认情况下是可见的,可采用如下代码(这里 user_ns 是用于执行交互式输入代码的模块):
123 | import warningswarnings.filterwarnings("default", category=DeprecationWarning, module=user_ns.get("__name__")) |
|---|
如果明知正在使用会引起警告的代码,比如某个废弃函数,但不想看到警告(即便警告已经通过命令行作了显式配置),那么可以使用 catch_warnings 上下文管理器来抑制警告。
12345678 | import warningsdef fxn(): warnings.warn("deprecated", DeprecationWarning)with warnings.catch_warnings(): warnings.simplefilter("ignore") fxn() |
|---|
catch_warnings上下文管理器,行为不可预知。catch_warnings上下文管理器。有了它,就可以临时改变警告过滤器以方便测试。例如,以下代码可捕获所有的警告以便查看:1234567891011121314 | 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 规则而被引发,那么无论设置什么过滤器,该条警告都不会再出现,除非该警告有关的注册数据被清除。
showwarning()函数也被恢复到初始值。
catch_warnings上下文管理器,行为未定义。
DeprecationWarning (适用于每个模块,除了 __main__),这意味着开发人员应该确保在测试代码时应将通常忽略的警告显示出来,以便未来破坏性 API 变化时及时收到通知(无论是在标准库还是第三方包)。
unittest 模块提供的测试运行程序就是如此)。
-Wd (这是 -W default 的简写) 或设置环境变量 PYTHONWARNINGS=default 来检查应用程序是否用到了已弃用的接口。 这样可以启用对所有警告的默认处理操作,包括那些默认忽略的警告。 要改变遇到警告后执行的动作,可以改变传给 -W的参数 (例如 -W error)。 请参阅 -W旗标来了解更多的细节。
UserWarning。 或者 message 可为 Warning的实例,这时 category 将被忽略,转而采用 message.__class__。 在这种情况下,错误信息文本将是 str(message)。 如果某条警告被 警告过滤器改成了错误,本函数将触发一条异常。 参数 stacklevel 可供 Python 包装函数使用,比如:def deprecation(message): warnings.warn(message, DeprecationWarning, stacklevel=2) 这会让警告指向 deprecation() 的调用者,而不是 deprecation() 本身的来源(因为后者会破坏引发警告的目的)。source 是发出 ResourceWarning 的被销毁对象。
warn() 函数的底层接口,显式传入消息、类别、文件名和行号,以及可选的模块名和注册表(应为模块的 __warningregistry__ 字典)。 模块名称默认为去除了 .py 的文件名;如果未传递注册表,警告就不会被抑制。 message 必须是个字符串,category 是 Warning的子类;或者message 可为 Warning的实例,且 category 将被忽略。module_globals 应为发出警告的代码所用的全局命名空间。(该参数用于从 zip 文件或其他非文件系统导入模块时显式源码)。source 是发出 ResourceWarning 的被销毁对象。
formatwarning(message, category, filename, lineno, line) 并将结果字符串写入 file ,默认文件为 sys.stderr。通过将任何可调用对象赋给 warnings.showwarning 可替换掉该函数。line 是要包含在警告信息中的一行源代码;如果未提供 line,showwarning() 将尝试读取由filename 和 lineno 指定的行。
formatwarning() 将尝试读取由 filename 和 lineno 指定的行。
filterwarnings()相同,但不需要正则表达式,因为插入的过滤器总是匹配任何模块中的任何信息,只要类别和行号匹配即可。
filterwarnings()的所有调用,包括 -W 命令行选项和对 simplefilter()的调用效果。
showwarning() 函数,并在退出时恢复。 如果 record 参数是 False (默认),则在进入时会返回 None 。 如果 record 为 True ,则返回一个列表,列表由自定义 showwarning() 函数所用对象逐步填充(该函数还会抑制 sys.stdout 的输出)。 列表中每个对象的属性与 showwarning() 的参数名称相同。module 参数代表一个模块,当导入 warnings 时,将被用于代替返回的模块,其过滤器将被保护。该参数主要是为了测试 warnings 模块自身。If the action argument is not None, the remaining arguments are passed to simplefilter() as if it were called immediately on entering the context.备注 catch_warnings 管理器的工作方式,是替换并随后恢复模块的 showwarning()