Python 我怎样才能捕捉到这样的警告';这是个例外(不仅仅是测试)?

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

我必须用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

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

您的配置似乎正在使用打印选项:

这意味着您看到的警告不是真正的警告,而是打印到标准输出的一些字符(有关详细信息,请参阅文档)。如果你想抓住它,你可以:

  • 使用将直接引发异常的
    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: 
    

    您的配置似乎正在使用
    打印
    选项:

    这意味着您看到的警告不是真正的警告,而是打印到标准输出的一些字符(有关详细信息,请参阅文档)。如果你想抓住它,你可以:

  • 使用将直接引发异常的
    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 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.
    re