在 Python 中,如何将警告当作异常来捕捉?

我在 Python 代码中使用的第三方库(用 C 编写)正在发出警告。我希望能够使用 try except语法来正确处理这些警告。有办法吗?

128305 次浏览

引用 Python 手册(27.6.4测试警告) :

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)

这里有一个变体,可以更清楚地说明如何只使用自定义警告。

import warnings
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")


# Call some code that triggers a custom warning.
functionThatRaisesWarning()


# ignore any non-custom warnings that may be in the list
w = filter(lambda i: issubclass(i.category, UserWarning), w)


if len(w):
# do something with the first warning
email_admins(w[0].message)

要将警告作为错误处理,只需使用以下命令:

import warnings
warnings.filterwarnings("error")

在此之后,您将能够捕获与错误相同的警告,例如,这将工作:

try:
some_heavy_calculations()
except RuntimeWarning:
breakpoint()

增加了这个答案,因为评论中的最佳答案包含拼写错误: filterwarnigns而不是 filterwarnings

如果您只是希望您的脚本在出现警告时失败,那么您可以使用 -W参数调用 python:

python -W error foobar.py

在某些情况下,您需要使用 ctype 将警告转换为错误,例如:

str(b'test')  # no error
import warnings
warnings.simplefilter('error', BytesWarning)
str(b'test')  # still no error
import ctypes
ctypes.c_int.in_dll(ctypes.pythonapi, 'Py_BytesWarningFlag').value = 2
str(b'test')  # this raises an error

Niekas 回答上展开,但使用上下文退出后将警告行为重置为默认的 catch_warnings上下文管理器:

import warnings


with warnings.catch_warnings():
warnings.simplefilter("error")
# Code in this block will raise exception for a warning
# Code in this block will have default warning behaviour

为了完整起见,您还可以导出一个 env 变量:

PYTHONWARNINGS=error /usr/bin/run_my_python_utility

捕捉所有的警告是有问题的。你可以捕捉特定的警告。例如,我需要捕捉枕头的警告:

import warnings
warnings.filterwarnings("error", category=Image.DecompressionBombWarning)


def process_images():
try:
some_process()


except Image.DecompressionBombWarning as e:
print(e)