为了账号安全,请及时绑定邮箱和手机立即绑定

如何捕获像异常一样的Numpy警告(不仅用于测试)?

如何捕获像异常一样的Numpy警告(不仅用于测试)?

有只小跳蛙 2019-11-11 14:42:34
我必须在Python中为正在执行的项目制作Lagrange多项式。我正在做一个重心样式,以避免使用显式的for循环,而不是牛顿的分差样式。我遇到的问题是我需要用零除,但是Python(或者也许是numpy)只是将其警告而不是正常异常。因此,我需要知道的是如何捕获此警告,就像它是一个例外一样。我在本网站上发现的与此相关的问题并未按照我需要的方式回答。这是我的代码:import numpy as npimport matplotlib.pyplot as pltimport warningsclass Lagrange:    def __init__(self, xPts, yPts):        self.xPts = np.array(xPts)        self.yPts = np.array(yPts)        self.degree = len(xPts)-1         self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])    def __call__(self, x):        warnings.filterwarnings("error")        try:            bigNumerator = np.product(x - self.xPts)            numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])            return sum(numerators/self.weights*self.yPts)         except Exception, e: # Catch division by 0. Only possible in 'numerators' array            return yPts[np.where(xPts == x)[0][0]]L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2L(1) # This should catch an error, then return 1. 执行此代码后,我得到的输出是:Warning: divide by zero encountered in int_scalars那是我要抓住的警告。它应该出现在列表理解中。
查看完整描述

3 回答

?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

看来您的配置正在使用print选项numpy.seterr:


>>> import numpy as np

>>> np.array([1])/0   #'warn' mode

__main__:1: RuntimeWarning: divide by zero encountered in divide

array([0])

>>> np.seterr(all='print')

{'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}

>>> np.array([1])/0   #'print' mode

Warning: divide by zero encountered in divide

array([0])

这意味着您看到的警告不是真正的警告,而只是印有一些字符stdout(请参阅文档以获取有关信息seterr)。如果您想抓住它,可以:


使用numpy.seterr(all='raise')它将直接引发异常。但是,这会更改所有操作的行为,因此,这是行为上的很大变化。

使用numpy.seterr(all='warn'),可以将打印的警告转换为真实的警告,您将可以使用上述解决方案来本地化此行为更改。

实际warnings收到警告后,您可以使用该模块来控制警告的处理方式:


>>> import warnings

>>> 

>>> warnings.filterwarnings('error')

>>> 

>>> try:

...     warnings.warn(Warning())

... except Warning:

...     print 'Warning was raised as an exception!'

... 

Warning was raised as an exception!

请仔细阅读文档,filterwarnings因为它可以使您仅过滤所需的警告并具有其他选项。我还要考虑看看catch_warnings哪个是上下文管理器,它会自动重置原始filterwarnings功能:


>>> import warnings

>>> with warnings.catch_warnings():

...     warnings.filterwarnings('error')

...     try:

...         warnings.warn(Warning())

...     except Warning: print 'Raised!'

... 

Raised!

>>> try:

...     warnings.warn(Warning())

... except Warning: print 'Not raised!'

... 

__main__:2: Warning: 


查看完整回答
反对 回复 2019-11-11
?
翻翻过去那场雪

TA贡献2065条经验 获得超14个赞

如果您已经知道警告可能在何处发生,那么使用numpy.errstate上下文管理器通常会更干净一些,而不是 numpy.seterr将所有相同类型的后续警告都视为相同,而不管它们在代码中的位置如何:


import numpy as np


a = np.r_[1.]

with np.errstate(divide='raise'):

    try:

        a / 0   # this gets caught and handled as an exception

    except FloatingPointError:

        print('oh no!')

a / 0           # this prints a RuntimeWarning as usual

编辑:

在我最初的示例中,我有a = np.r_[0],但是显然numpy的行为发生了变化,使得在分子为全零的情况下,以零除的处理方式有所不同。例如,在numpy 1.16.4中:


all_zeros = np.array([0., 0.])

not_all_zeros = np.array([1., 0.])


with np.errstate(divide='raise'):

    not_all_zeros / 0.  # Raises FloatingPointError


with np.errstate(divide='raise'):

    all_zeros / 0.  # No exception raised


with np.errstate(invalid='raise'):

    all_zeros / 0.  # Raises FloatingPointError

相应的警告消息也不同:1. / 0.记录为RuntimeWarning: divide by zero encountered in true_divide,而0. / 0.记录为RuntimeWarning: invalid value encountered in true_divide。我不知道到底为什么这种变化作出的,但我怀疑它有与事实结果做0. / 0.是不能表示为数字(numpy的回报为NaN在这种情况下),而1. / 0.并-1. / 0.分别返回+ Inf文件和-Inf ,符合IEE 754标准。


如果要捕获两种类型的错误,则可以始终通过np.errstate(divide='raise', invalid='raise'),或者all='raise'如果您想对任何类型的浮点错误引发异常。


查看完整回答
反对 回复 2019-11-11
?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

我发现这使我能够以类似于捕获错误警告的方式捕获运行时警告,从而很好地打印警告:


import warnings


with warnings.catch_warnings():

    warnings.filterwarnings('error')

    try:

        answer = 1 / 0

    except Warning as e:

        print('error found:', e)

您可能可以尝试放置warnings.catch_warnings()的位置,具体取决于您要使用这种方式捕获错误的伞的大小。

查看完整回答
反对 回复 2019-11-11
  • 3 回答
  • 0 关注
  • 1504 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信