我如何捕捉 numpy 警告,就像它是一个例外(不仅仅是为了测试)? [英] How do I catch a numpy warning like it's an exception (not just for testing)?

查看:26
本文介绍了我如何捕捉 numpy 警告,就像它是一个例外(不仅仅是为了测试)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须在 Python 中为我正在做的项目创建一个拉格朗日多项式.我正在做一种以重心为中心的风格,以避免使用显式的 for 循环,而不是牛顿的划分差异风格.我遇到的问题是我需要捕获除以零,但是 Python(或者可能是 numpy)只是使它成为警告而不是正常异常.

所以,我需要知道如何做的是捕捉这个警告,就好像它是一个例外一样.我在本网站上找到的与此相关的问题没有以我需要的方式回答.这是我的代码:

将 numpy 导入为 np导入 matplotlib.pyplot 作为 plt进口警告拉格朗日类:def __init__(self, xPts, yPts):self.xPts = np.array(xPts)self.yPts = np.array(yPts)self.degree = len(xPts)-1self.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("错误")尝试:bigNumerator = np.product(x - self.xPts)numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])返回总和(分子/self.weights*self.yPts)except Exception, e: # 捕捉除以 0.仅在 'numerators' 数组中可用返回 yPts[np.where(xPts == x)[0][0]]L = Lagrange([-1,0,1],[1,0,1]) # 创建二次多边形 L(x) = x^2L(1) # 这应该捕获一个错误,然后返回 1.

当这段代码被执行时,我得到的输出是:

警告:在 int_scalars 中遇到除以零

这就是我想要捕捉的警告.它应该出现在列表推导式中.

解决方案

看来您的配置正在使用 numpy.seterr:

<预><代码>>>>将 numpy 导入为 np>>>np.array([1])/0 #'警告' 模式__main__:1: RuntimeWarning: 除以零遇到除法数组([0])>>>np.seterr(all='print'){'over':'warn','divide':'warn','invalid':'warn','under':'ignore'}>>>np.array([1])/0 #'打印'模式警告:在除法中遇到除以零数组([0])

这意味着您看到的警告不是真正的警告,而只是将一些字符打印到stdout(请参阅seterr).如果你想抓住它,你可以:

  1. 使用 numpy.seterr(all='raise') 将直接引发异常.然而,这会改变所有操作的行为,因此这是一个相当大的行为变化.
  2. 使用 numpy.seterr(all='warn'),它会将打印的警告转换为真正的警告,您将能够使用上述解决方案来定位这种行为变化.

一旦你真的有警告,你可以使用warnings模块来控制应该如何处理警告:

<预><代码>>>>进口警告>>>>>>warnings.filterwarnings('错误')>>>>>>尝试:... warnings.warn(Warning())...除了警告:... print '警告是作为例外提出的!'...警告作为例外提出!

仔细阅读filterwarnings<的文档/a> 因为它允许您仅过滤您想要的警告并具有其他选项.我也会考虑查看 catch_warnings 这是一个上下文管理器,它会自动重置原始的 filterwarnings 函数:

<预><代码>>>>进口警告>>>使用 warnings.catch_warnings():... warnings.filterwarnings('错误')... 尝试:... warnings.warn(Warning())... 除了警告:打印 'Raised!'...提高!>>>尝试:... warnings.warn(Warning())...除了警告:打印未提出!"...__main__:2: 警告:

I have to make a Lagrange polynomial in Python for a project I'm doing. I'm doing a barycentric style one to avoid using an explicit for-loop as opposed to a Newton's divided difference style one. The problem I have is that I need to catch a division by zero, but Python (or maybe numpy) just makes it a warning instead of a normal exception.

So, what I need to know how to do is to catch this warning as if it were an exception. The related questions to this I found on this site were answered not in the way I needed. Here's my code:

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. 

When this code is executed, the output I get is:

Warning: divide by zero encountered in int_scalars

That's the warning I want to catch. It should occur inside the list comprehension.

解决方案

It seems that your configuration is using the print option for 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])

This means that the warning you see is not a real warning, but it's just some characters printed to stdout(see the documentation for seterr). If you want to catch it you can:

  1. Use numpy.seterr(all='raise') which will directly raise the exception. This however changes the behaviour of all the operations, so it's a pretty big change in behaviour.
  2. Use numpy.seterr(all='warn'), which will transform the printed warning in a real warning and you'll be able to use the above solution to localize this change in behaviour.

Once you actually have a warning, you can use the warnings module to control how the warnings should be treated:

>>> import warnings
>>> 
>>> warnings.filterwarnings('error')
>>> 
>>> try:
...     warnings.warn(Warning())
... except Warning:
...     print 'Warning was raised as an exception!'
... 
Warning was raised as an exception!

Read carefully the documentation for filterwarnings since it allows you to filter only the warning you want and has other options. I'd also consider looking at catch_warnings which is a context manager which automatically resets the original filterwarnings function:

>>> 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 警告,就像它是一个例外(不仅仅是为了测试)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆