我如何捕捉像是一个exception(不只是为了testing)的一个numpy警告?

我必须在Python中为一个项目制作拉格朗日多项式。 为了避免使用明确的for循环而不是牛顿的不同的风格,我正在做一个重心式的风格。 我遇到的问题是我需要通过零来捕捉一个除法,但是Python(或者可能是numpy)只是使它成为警告而不是正常的exception。

所以,我需要知道怎么做就是把这个警告看作是一个例外。 我在这个网站上find的相关问题不是以我需要的方式回答的。 这是我的代码:

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 

这是我想要捕捉的警告。 它应该发生在列表理解中。

看来您的configuration正在使用numpy.seterrprint选项:

 >>> 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的文档)。 如果你想抓住它,你可以:

  1. 使用numpy.seterr(all='raise')会直接引发exception。 然而,这改变了所有操作的行为,所以这是一个非常大的行为变化。
  2. 使用numpy.seterr(all='warn') ,它会将打印的警告转换为真实的警告,并且您将能够使用上述解决scheme来本地化这种更改行为。

一旦你真的有警告,你可以使用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! 

请仔细阅读filter警告的文档,因为它允许您只过滤所需的警告并具有其他选项。 我也考虑看catch_warnings这是一个上下文pipe理器,它会自动重置原始的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: 

给@ Bakuriu的答案补充一点:

如果您已经知道可能发生警告的位置,那么使用numpy.errstate上下文pipe理器通常更清洁,而不是使用numpy.seterr ,它将所有相同types的后续警告视为相同,无论它们在您的代码中发生的位置如何:

 import numpy as np a = np.r_[0] 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 

为了详细说明@ Bakuriu上面的答案,我发现这使我能够以类似的方式捕获运行时警告,以便捕获错误警告,并很好地打印出警告:

 import warnings with warnings.catch_warnings(): warnings.filterwarnings('error') try: answer = 1 / 0 except Warning as e: print('error found:', e) 

您可能可以通过放置warnings.catch_warnings()放置来实现这个function,具体取决于您要使用这种捕捉错误来投射的伞的大小。