我必须在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
型
这就是我想捕捉的警告。它应该出现在列表解析中。
6条答案
按热度按时间j2qf4p5b1#
您的配置似乎正在为
numpy.seterr
使用print
选项:字符串
这意味着您看到的警告不是一个真实的警告,而只是打印到
stdout
的一些字符(请参阅seterr
的文档)。如果您想捕获它,您可以:1.使用
numpy.seterr(all='raise')
,它将直接引发异常。然而,这会改变所有操作的行为,所以这是一个相当大的行为变化。1.使用
numpy.seterr(all='warn')
,它将把打印的警告转换为真实的警告,您将能够使用上述解决方案来本地化此行为更改。一旦你真的有了一个警告,你可以使用
warnings
模块来控制如何处理警告:型
仔细阅读
filterwarnings
的文档,因为它允许你只过滤你想要的警告,并且有其他选项。我还考虑看看catch_warnings
,它是一个上下文管理器,可以自动重置原始的filterwarnings
函数:型
2exbekwf2#
在@Bakuriu的回答中添加一点:
如果你已经知道警告可能发生在哪里,那么使用
numpy.errstate
上下文管理器通常会更干净,而不是numpy.seterr
,它会将相同类型的所有后续警告都视为相同,而不管它们在代码中发生在哪里:字符串
编辑:
在我最初的例子中,我有
a = np.r_[0]
,但显然numpy的行为发生了变化,在分子为全零的情况下,被零除的处理方式有所不同。例如,在numpy 1.16.4中:型
相应的警告信息也不同:
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'
,如果你想在任何类型的浮点错误上引发异常。hvvq6cgz3#
为了详细说明@Bakuriu上面的答案,我发现这使我能够以类似于捕获错误警告的方式捕获运行时警告,并很好地打印出警告:
字符串
你可能可以根据你想用这种方式捕捉错误的伞的大小来尝试放置warnings.catch_warnings()的位置。
sycxhyv74#
删除warnings.filterwarnings并添加:
字符串
hmmo2u0o5#
字符串
这可能是一个更好的例子。
lmyy7pcs6#
如果我可以建议这个选项,一个很好的Python方法是使用上下文管理器。之前的另一个答案提供了这个想法,但我花了一点时间来弄清楚如何使用它,所以我补充了答案。
Python 3.11
之前,你必须在不同的行上写所需的操作(这是实现它的方法,我检查了文档,见下文)。Python 3.11
之后,您可以以一种非常简洁的方式将操作传递给上下文管理器的构造函数。参见下面的示例。
字符串