Python 我怎样才能捕捉到这样的警告';这是个例外(不仅仅是测试)?
我必须用Python为我正在做的一个项目制作一个拉格朗日多项式。我在做重心式的,避免使用显式的for循环,而不是牛顿的分差式。我遇到的问题是,我需要捕获一个除法为零的除法,但是Python(或者可能是numpy)只是将其作为一个警告,而不是一个正常的异常 所以,我需要知道如何捕捉这个警告,就像它是一个例外一样。我在这个网站上发现的相关问题没有以我需要的方式得到回答。这是我的密码:Python 我怎样才能捕捉到这样的警告';这是个例外(不仅仅是测试)?,python,exception,numpy,warnings,divide-by-zero,Python,Exception,Numpy,Warnings,Divide By Zero,我必须用Python为我正在做的一个项目制作一个拉格朗日多项式。我在做重心式的,避免使用显式的for循环,而不是牛顿的分差式。我遇到的问题是,我需要捕获一个除法为零的除法,但是Python(或者可能是numpy)只是将其作为一个警告,而不是一个正常的异常 所以,我需要知道如何捕捉这个警告,就像它是一个例外一样。我在这个网站上发现的相关问题没有以我需要的方式得到回答。这是我的密码: import numpy as np import matplotlib.pyplot as plt import
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
这就是我想要抓住的警告。它应该出现在列表理解中。您的配置似乎正在使用打印选项: 这意味着您看到的警告不是真正的警告,而是打印到标准输出的一些字符(有关详细信息,请参阅文档)。如果你想抓住它,你可以:
numpy.seterr(all='raise')
。然而,这改变了所有操作的行为,因此这是一个相当大的行为变化numpy.seterr(all='warn')
,这将把打印的警告转换为真实的警告,您将能够使用上述解决方案来定位这种行为变化警告
模块控制如何处理警告:
>>> import warnings
>>>
>>> warnings.filterwarnings('error')
>>>
>>> try:
... warnings.warn(Warning())
... except Warning:
... print 'Warning was raised as an exception!'
...
Warning was raised as an exception!
请仔细阅读的文档,因为它只允许您过滤所需的警告,并且有其他选项。我也会考虑查看哪一个是上下文管理器,它自动重置原来的<代码>过滤警告< /代码>函数:
>>> 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的回答补充一点: 如果您已经知道警告可能发生在何处,那么使用上下文管理器通常更为简洁,而不是将相同类型的所有后续警告视为相同,而不管它们发生在代码中的何处:
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\u0]
,但很明显,numpy的行为发生了变化,在分子都为零的情况下,被零除的处理方式有所不同。例如,在numpy 1.16.4中:
all_zeros=np.array([0,0.])
非全零=np.数组([1,0.])
使用np.errstate(divide='raise'):
不是所有的零/0引发浮点错误
使用np.errstate(divide='raise'):
全零/0没有提出例外
使用np.errstate(invalid='raise'):
全零/0引发浮点错误
相应的警告消息也不同:1./0。
记录为RuntimeWarning:true\u divide中遇到的除零
,而0。/0.
记录为运行时警告:在true\u divide中遇到无效值
。我不知道为什么会做出这样的更改,但我怀疑这与0的结果有关0。
不能表示为数字(在本例中,numpy返回一个NaN),而1。/0.
和-1./0.
根据IEE 754标准分别返回+Inf和-Inf
如果您想捕获这两种类型的错误,您可以始终传递
np.errstate(divide='raise',invalid='raise')
,或者all='raise'
,如果您想对任何类型的浮点错误引发异常。要详细说明@Bakuriu的上述答案,我发现这使我能够以类似于捕获错误警告的方式捕获运行时警告,并很好地打印出警告:
import warnings
with warnings.catch_warnings():
warnings.filterwarnings('error')
try:
answer = 1 / 0
except Warning as e:
print('error found:', e)
您可能可以随意放置警告。catch_warnings()的放置取决于您希望以这种方式放置多大的伞来捕捉错误。删除警告。过滤警告并添加:
numpy.seterr(all='raise')
我认为这是一个开始。但这并不能解决我的问题。如果我在try块的代码中添加warnings.warn(Warning()),它将捕获该警告。出于某种原因,它没有捕捉到被零除的警告。下面是确切的警告消息:警告:在int中遇到被零除的情况_scalars@JohnK. 您应该编辑您的问题并添加准确的输出,否则我们无法判断出问题所在。numpy可能在某个地方定义了这个警告类,您必须发现哪个子包能够捕获它。没关系,我发现您应该使用
RuntimeWarning
。更新了答案。你确定吗?我已将代码更改为除RuntimeWarning:之外的其他用途。它仍然不起作用。在文档中,它声明会引发运行时警告。问题可能是您的numpy配置使用的是打印
选项,该选项仅打印警告,但它不是由警告
模块处理的真正警告。。。如果是这种情况,您可以尝试使用numpy.seterr(all='warn')
并重试。在我的numpy
版本中,您不能使用numpy.seterr(all='error')
,error
需要是raise
。您确定它是警告:…
?尝试像np.array([1])/0这样的操作,我得到RuntimeWarning:…
作为输出。@madpysicator不是重复的;NumPy在蟒蛇之上有自己的内部警告架构,可以专门控制(见Bakuríu的答案)。@gerrit。我接受了纠正,学到了一件新东西。我删除了我最初的评论,以避免引发收集徽章的狂热。你可以使用的另一种方法是在除法之前简单地检查分母是否为0,这样就避免了摆弄numpy警告系统的开销。(尽管这可能意味着您必须将对整洁列表的理解扩展为循环检查分母是否为零。)值得注意的是,它会引发FloatingPointError
,而不是
numpy.seterr(all='raise')