How do I catch a numpy warning like it's an exception (not just for testing)?
我必须在Python中为我正在做的项目制作拉格朗日多项式。 我正在做一个重心的样式,以避免使用显式的for循环而不是Newton的分割差异样式。 我遇到的问题是我需要将除法除以零,但Python(或者可能是numpy)只是使它成为警告而不是正常的异常。
所以,我需要知道的是抓住这个警告,好像它是一个例外。 我在本网站上发现的相关问题没有按照我需要的方式回答。 这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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. |
执行此代码时,我得到的输出是:
1 | Warning: divide by zero encountered in int_scalars |
这是我想要捕捉的警告。 它应该出现在列表理解中。
您的配置似乎正在使用
1 2 3 4 5 6 7 8 9 | >>> 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]) |
这意味着您看到的警告不是真正的警告,但只是打印到
实际发出警告后,您可以使用
1 2 3 4 5 6 7 8 9 10 | >>> import warnings >>> >>> warnings.filterwarnings('error') >>> >>> try: ... warnings.warn(Warning()) ... except Warning: ... print 'Warning was raised as an exception!' ... Warning was raised as an exception! |
请仔细阅读
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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的回答:
如果您已经知道可能发生警告的位置,那么使用
1 2 3 4 5 6 7 8 9 | 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 |
编辑:
在我的原始示例中,我有
1 2 3 4 5 6 7 8 9 10 11 | 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 |
相应的警告消息也不同:
如果要捕获这两种类型的错误,如果要在任何类型的浮点错误上引发异常,则可以始终传递
为了详细说明@ Bakuriu上面的答案,我发现这使我能够以类似的方式捕获运行时警告,以便我如何捕获错误警告,很好地打印出警告:
1 2 3 4 5 6 7 8 | import warnings with warnings.catch_warnings(): warnings.filterwarnings('error') try: answer = 1 / 0 except Warning as e: print('error found:', e) |
您可能可以使用warnings.catch_warnings()放置,这取决于您希望通过这种方式捕获错误来构建多大的伞。
删除warnings.filterwarnings并添加:
1 | numpy.seterr(all='raise') |