【问题标题】:In Python, how does one catch warnings as if they were exceptions?在 Python 中,如何将警告视为异常?
【发布时间】:2011-08-04 10:17:51
【问题描述】:

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

【问题讨论】:

  • 那些警告只是写做标准错误的短信吗?
  • Fenikso:我不确定,好像是真的警告
  • 如何识别“真正的警告”?我认为在 C 中你会在编译期间得到真正的警告。
  • warnings.filterwarnings 完全符合您的要求,我不明白您的问题是什么?
  • @Fenikso,@Rosh Oxymoron 你是对的。我的错。 warnings.filterwarnigns('error') 完成这项工作。我找不到提出此解决方案的原始答案

标签: python exception exception-handling warnings


【解决方案1】:

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

import warnings
warnings.filterwarnings("error")

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

try:
    some_heavy_calculations()
except RuntimeWarning:
    import ipdb; ipdb.set_trace()

附:添加此答案是因为 cmets 中的最佳答案包含拼写错误:filterwarnigns 而不是 filterwarnings

【讨论】:

  • 如果你只想查看堆栈跟踪,前两行就足够了。
  • 这是完美的。我只是希望我的脚本在发出警告后立即停止执行,以便我可以打印相关的调试信息并修复问题。
  • 您不需要调用filterwarnings 来捕获Warnings,至少在python 3 中是这样。它可以正常工作。
  • 接受的答案不回答 OP 的问题。这个答案可以。这是我在搜索找到此问题时正在寻找的答案。
  • 如果您在较大的脚本或软件包中使用此功能,将所有警告转换为错误很容易出现问题。也会使调试变得非常困难
【解决方案2】:

引用python手册(27.6.4. Testing Warnings):

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)

【讨论】:

  • Here 是一个答案,它告诉您如何使用try except 语法。
  • 与 niekas 的回答相比,这具有优势,即如果 fnx 返回某些内容,您可以保留该结果(并且仍然可以管理警告)。
  • 这并不能回答 OP 的问题,即处理 wanrings,而不是测试它们。但是,下面 niekas 的回答确实显示了如何处理警告。
  • 请注意,如果您的函数只是间歇性地返回警告,则上述函数将不起作用,因为如果fxn() 没有返回警告,那么w 将是一个空列表。如果w 是一个空列表(即[]),那么运行代码会给你以下错误:IndexError: list index out of range。如果您只是想格式化或检查捕获的警告的属性,那么最好使用 for 循环:for x in w: print(f'{x.category.__name__}: {str(x.message)}')
  • 如果想在不中断程序执行的情况下处理警告,这种方法很有用。
【解决方案3】:

如果您只想让脚本因警告而失败,您可以使用 -W argument 调用 python

python -W error foobar.py

【讨论】:

  • 捕获特定的警告类型,例如:python -W error::RuntimeWarning foobar.py
【解决方案4】:

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

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)

【讨论】:

    【解决方案5】:

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

    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
    

    【讨论】:

    • 这个答案是建设性的,只是为了展示如何仅在某些警告类型中出错。对于几乎任何大型软件项目,如果您执行warnings.simplefilter('error'),您将不会获得您在日志中看到的警告的回溯,而是从先前过滤的警告中获得回溯。如果您有一些 CLI 调用,使用 simplefilter 也是获得答案的最快方法。
    【解决方案6】:

    niekas answer 上扩展,但使用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
    

    【讨论】:

      【解决方案7】:

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

      PYTHONWARNINGS=error /usr/bin/run_my_python_utility
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-17
        • 2020-01-18
        • 2011-03-15
        • 2021-05-29
        • 1970-01-01
        • 2018-05-22
        • 2013-10-21
        相关资源
        最近更新 更多