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

我必须在Python中为正在执行的项目制作Lagrange多项式。我正在做一个重心样式,以避免使用显式的for循环,而不是牛顿的分差样式。我遇到的问题是我需要用零除,但是Python(或者也许是numpy)只是将其警告而不是正常异常。


因此,我需要知道的是如何捕获此警告,就像它是一个例外一样。我在本网站上发现的与此相关的问题并未按照我需要的方式回答。这是我的代码:


import numpy as np

import matplotlib.pyplot as plt

import warnings


class 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^2


L(1) # This should catch an error, then return 1. 

执行此代码后,我得到的输出是:


Warning: divide by zero encountered in int_scalars

那是我要抓住的警告。它应该出现在列表理解中。


有只小跳蛙
浏览 1505回答 3
3回答

慕盖茨4494581

看来您的配置正在使用print选项numpy.seterr:>>> import numpy as np>>> np.array([1])/0   #'warn' mode__main__:1: RuntimeWarning: divide by zero encountered in dividearray([0])>>> np.seterr(all='print'){'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}>>> np.array([1])/0   #'print' modeWarning: divide by zero encountered in dividearray([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: 

翻翻过去那场雪

如果您已经知道警告可能在何处发生,那么使用numpy.errstate上下文管理器通常会更干净一些,而不是 numpy.seterr将所有相同类型的后续警告都视为相同,而不管它们在代码中的位置如何:import numpy as npa = 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 FloatingPointErrorwith np.errstate(divide='raise'):    all_zeros / 0.  # No exception raisedwith 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'如果您想对任何类型的浮点错误引发异常。

拉风的咖菲猫

我发现这使我能够以类似于捕获错误警告的方式捕获运行时警告,从而很好地打印警告:import warningswith warnings.catch_warnings():    warnings.filterwarnings('error')    try:        answer = 1 / 0    except Warning as e:        print('error found:', e)您可能可以尝试放置warnings.catch_warnings()的位置,具体取决于您要使用这种方式捕获错误的伞的大小。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python