# How can I make my code continue despite exception?

I wrote a function that loops through a data array, performs some calculations and returns new arrays with the results. Unfortunately, some entries in the array contain zero values and cause a division by zero exception, which stops the code. Is there a way to generally ignore division by zero exceptions without wrapping every single line in a "try: except:" construct? Here is a very simplistic example:

var('a x y')
eq_y1 = y == a/x
eq_y2 = y == a*x
eq_y3 = y == a^x

def fun_loop(in_array):
out_array1 = np.zeros_like(in_array)
out_array2 = np.zeros_like(in_array)
out_array3 = np.zeros_like(in_array)
for i in srange(len(in_array)):
in_list = in_array[i]
for j in srange(len(in_list) - 1):
vdict = {}
vdict[a] = in_array[i][j]
vdict[x] = in_array[i][j+1]
out_array1[i,j] = eq_y1.rhs().subs(vdict)
out_array2[i,j] = eq_y2.rhs().subs(vdict)
out_array3[i,j] = eq_y3.rhs().subs(vdict)
return [out_array1, out_array2, out_array3]
in_array = np.array([[3,2,1],[2,1,3],[-3,-1,-2]])
fun_loop(in_array)


returns: [array([[1, 2, 0], [2, 0, 0], [3, 0, 0]]), array([[6, 2, 0], [2, 3, 0], [3, 2, 0]]), array([[9, 2, 0], [2, 1, 0], [0, 1, 0]])]

However:

in_array = np.array([[3,2,1],[2,1,3],[-3,-1,-2]])
fun_loop(in_array)


returns "ValueError: power::eval(): division by zero" and no results. I would like the function to still return the results for all the other cells, without wrapping each line of the code in a try-except construct. Is there a way to define a general rule how to deal with exeptions of a certain kind within a function like that? The reason is that I have many different equations in the real function and don't want to make the code three times longer.

edit retag close merge delete

Sort by » oldest newest most voted

You can express "general rules" like this as wrapper functions. In your case you might want to write something along the lines of:

def subs_or_none(expr, vdict):
try:
return expr.subs(vdict)
except ValueError:
return None


and then you can write

    out_array1[i,j] = subs_or_none(eq_y1.rhs(), vdict)
...


Your code is still a bit longer, because you have to specify how to handle the exception (but you really need to do that anyway). Your cost does not go up with the number of times you need the behaviour, however.

Be careful that this code would catch all ValueErrors. You'd need to do some more checking to ensure it's just a division-by-zero. In fact, one could consider it a deficiency that pynac signals a ValueError here and not a ZeroDivisionError.

more

Awesome, thank you! This does the trick with only small alterations to the code. Just a small comment, unless insisting on an integer dtype in the array, it would be better to use NaN instead of None. See here for a discussion of NaN vs. None: http://stackoverflow.com/questions/17...

Using an inline if then else statement might do it. Below, I assume the equations involved are rational functions, but it works for that case. You might be able to adapt this idea to your specific situation.

var('a x y')
eq_y1 = y == a/x
eq_y2 = y == a*x
eq_y3 = y == a^x

def fun_loop(in_array):
out_array1 = np.zeros_like(in_array)
out_array2 = np.zeros_like(in_array)
out_array3 = np.zeros_like(in_array)
for i in srange(len(in_array)):
in_list = in_array[i]
for j in srange(len(in_list) - 1):
vdict = {}
vdict[a] = in_array[i][j]
vdict[x] = in_array[i][j+1]
out_array1[i,j] = eq_y1.rhs().subs(vdict) if eq_y1.rhs().denominator().subs(vdict)!=0 else 0
out_array2[i,j] = eq_y2.rhs().subs(vdict)
out_array3[i,j] = eq_y3.rhs().subs(vdict)
return [out_array1, out_array2, out_array3]
in_array = np.array([[3,2,1],[2,1,3],[-3,-1,-2]])
fun_loop(in_array)

more

Thanks, but this is quite similar to wrapping each line in a try-exception statement, only using if-else instead. I was wondering if one could not wrap the whole function in something that would continue evaluation every time a division by zero exception is thrown.