How can I catch a numpy warning as an exception (not just for testing)?

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

So, I need to know how to do this, to catch this warning, as if it were an exception. The related questions that I found on this site were not answered as I needed. Here is 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 the following:

 Warning: divide by zero encountered in int_scalars 

This is a warning that I want to catch. This should happen inside the list comprehension.

+143
python numpy exception warnings divide-by-zero
Apr 10 '13 at 18:36
source share
4 answers

It seems your configuration is using the print parameter 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 only some characters are printed on stdout (see documentation for seterr ). If you want to catch him, you can:

  • Use numpy.seterr(all='raise') , which will directly throw an exception. This, however, changes the behavior of all operations, so this is a pretty big change in behavior.
  • Use numpy.seterr(all='warn') , which converts the printed warning into a real warning, and you can use the above solution to localize this change in behavior.

Once you have a warning, you can use the warnings module to control the processing of alerts:

 >>> 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 the documentation for filterwarnings , as it allows you to filter only the required warning and has other parameters. I would also like to consider catch_warnings , which is a context manager that 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: 
+168
Apr 10 '13 at 18:53
source share

To add a little @Bakuriu answer:

If you already know where the warning may occur, it is better to use the numpy.errstate context manager, rather than numpy.seterr which processes all subsequent warnings of the same type, regardless of where they appear in your code:

 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 



Edit:

In my original example, I had a = np.r_[0] , but apparently there was a change in the behavior of numpy, so division by zero is handled differently when the numerator is all zeros. For example, in numpy 1.16.4:

 all_zeros = np.array([0., 0.]) not_all_zeros = np.array([1., 0.]) with np.errstate(divide='raise'): not_all_zeros / 0. # Raises FloatingPointError with np.errstate(divide='raise'): all_zeros / 0. # No exception raised with np.errstate(invalid='raise'): all_zeros / 0. # Raises FloatingPointError 

Relevant warning messages also vary: 1./0. registered as RuntimeWarning: divide by zero encountered in true_divide , whereas 0./0. registered as RuntimeWarning: invalid value encountered in true_divide . I'm not sure why this change was made, but I suspect that this is due to the fact that the result is 0./0. cannot be represented as a number (numpy returns NaN in this case), whereas 1./0. and -1./0. -1./0. return + Inf and -Inf, respectively, in accordance with the IEE 754 standard.

If you want to catch both types of errors, you can always pass np.errstate(divide='raise', invalid='raise') or all='raise' if you want to throw an exception for any type of floating point error,

+33
Nov 13 '15 at 21:21
source share

To talk more about @Bakuriu's answer above, I found that this allows me to detect a warning at runtime in the same way that I catch an error warning by printing the warning beautifully:

 import warnings with warnings.catch_warnings(): warnings.filterwarnings('error') try: answer = 1 / 0 except Warning as e: print('error found:', e) 

You can probably play around with the warnings.catch_warnings () location, depending on how big the umbrella you want to use is with error traps this way.

+23
Apr 7 '16 at 23:40
source share

Remove .filterwarnings warnings and add:

 numpy.seterr(all='raise') 
+4
Dec 20 '17 at 4:46 on
source share



All Articles