我如何捕捉一个非常规的警告(不只是为了测试)?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (18)

我必须用Python做一个拉格朗日多项式来完成我正在做的项目。为了避免使用显式的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

这就是我想抓住的警告。它应该发生在列表理解中。

提问于
用户回答回答于

似乎您的配置使用的是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。如果你想抓住它,你可以:

一旦您有了实际的警告,您可以使用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!

我也会考虑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 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 

扫码关注云+社区