Nice exception handling when re-trying code - python

I have some test cases. The test cases rely on data which takes time to compute. To speed up testing, I've cached the data so that it doesn't have to be recomputed.
I now have foo(), which looks at the cached data. I can't tell ahead of time what it will look at, as that depends a lot on the test case.
If a test case fails cause it doesn't find the right cached data, I don't want it to fail - I want it to compute the data and then try again. I also don't know what exception in particular it will throw cause of missing data.
My code right now looks like this:
if cacheExists:
loadCache()
dataComputed = False
else:
calculateData()
dataComputed = True
try:
foo()
except:
if not dataComputed:
calculateData()
dataComputed = True
try:
foo()
except:
#error handling code
else:
#the same error handling code
What's the best way to re-structure this code?

I disagree with the key suggestion in the existing answers, which basically boils down to treating exceptions in Python as you would in, say, C++ or Java -- that's NOT the preferred style in Python, where often the good old idea that "it's better to ask forgiveness than permission" (attempt an operation and deal with the exception, if any, rather than obscuring your code's main flow and incurring overhead by thorough preliminary checks). I do agree with Gabriel that a bare except is hardly ever a good idea (unless all it does is some form of logging followed by a raise to let the exception propagate). So, say you have a tuple with all the exception types that you do expect and want to handle the same way, say:
expected_exceptions = KeyError, AttributeError, TypeError
and always use except expected_exceptions: rather than bare except:.
So, with that out of the way, one slightly less-repetitious approach to your needs is:
try:
foo1()
except expected_exceptions:
try:
if condition:
foobetter()
else:
raise
except expected_exceptions:
handleError()
A different approach is to use an auxiliary function to wrap the try/except logic:
def may_raise(expected_exceptions, somefunction, *a, **k):
try:
return False, somefunction(*a, **k)
except expected_exceptions:
return True, None
Such a helper may often come in useful in several different situations, so it's pretty common to have something like this somewhere in a project's "utilities" modules. Now, for your case (no arguments, no results) you could use:
failed, _ = may_raise(expected_exceptions, foo1)
if failed and condition:
failed, _ = may_raise(expected_exceptions, foobetter)
if failed:
handleError()
which I would argue is more linear and therefore simpler. The only issue with this general approach is that an auxiliary function such as may_raise does not FORCE you to deal in some way or other with exceptions, so you might just forget to do so (just like the use of return codes, instead of exceptions, to indicate errors, is prone to those return values mistakenly being ignored); so, use it sparingly...!-)

Using blanket exceptions isn't usually a great idea. What kind of Exception are you expecting there? Is it a KeyError, AttributeError, TypeError...
Once you've identified what type of error you're looking for you can use something like hasattr() or the in operator or many other things that will test for your condition before you have to deal with exceptions.
That way you can clean up your logic flow and save your exception handling for things that are really broken!

Sometimes there's no nice way to express a flow, it's just complicated. But here's a way to call foo() in only one place, and have the error handling in only one place:
if cacheExists:
loadCache()
dataComputed = False
else:
calculateData()
dataComputed = True
while True:
try:
foo()
break
except:
if not dataComputed:
calculateData()
dataComputed = True
continue
else:
#the error handling code
break
You may not like the loop, YMMV...
Or:
if cacheExists:
loadCache()
dataComputed = False
else:
calculateData()
dataComputed = True
done = False
while !done:
try:
foo()
done = True
except:
if not dataComputed:
calculateData()
dataComputed = True
continue
else:
#the error handling code
done = True

I like the alternative approach proposed by Alex Martelli.
What do you think about using a list of functions as argument of the may_raise. The functions would be executed until one succeed!
Here is the code
def foo(x):
raise Exception("Arrrgh!")
return 0
def foobetter(x):
print "Hello", x
return 1
def try_many(functions, expected_exceptions, *a, **k):
ret = None
for f in functions:
try:
ret = f(*a, **k)
except expected_exceptions, e:
print e
else:
break
return ret
print try_many((foo, foobetter), Exception, "World")
result is
Arrrgh!
Hello World
1

Is there a way to tell if you want to do foobetter() before making the call? If you get an exception it should be because something unexpected (exceptional!) happened. Don't use exceptions for flow control.

Related

What is the role of else in try-except-else coupling in python?

So basically, else block for if-else coupling only work when if condition is not met so it is kind of necessary. In for-else coupling and while-else coupling, its executed when the loop cannot be executed for some reason. So, what we can not accomplished by not using else in try-except-else coupling. I meant if the reason is to detect if no exception is raised, we can simply put a print statement in the end of try block to achieve it. What is the vital role of else in try-except-else coupling?
(Hi all! I’m very new to programming and StackOverflow too. But I’ve tried to make the question as synced with decorum of site as possible)
So, what we can not accomplished by not using else in try-except-else coupling.
Consider
try:
a()
except Exception:
b()
else:
c()
A.
try:
a()
c()
except Exception:
b()
but that would catch and run b() if c() raises Exception. I believe this is probably what you are thinking of.
B.
try:
a()
except Exception:
b()
c()
but that could run c() when a() raises Exception.
C.
success = False
try:
a()
success = True
except Exception:
b()
if success:
c()
That is functionally equivalent, but more verbose and less clear. (And we haven't even included a finally block.)
try-except-else-finally is quite helpful for controlling the scope of caught errors.
There is no such thing as coupling in python for else. All the constructs you mentioned above coupled with else will work just fine without even using else. You can use if, for, while and try-except all without else. However, the role of else in python is: to execute a code instead of the code in block just above.
Note that it is irrelevant to else that what block is above it or with whom it is coupled. It will only be executed if the block above is not. And resultant block maybe or may not be vital or something which cannot be achieved by other means.
If there is no error found in try block the else block is also executed, but when a error is cached only except block will be executed.
So, if you have a method that could, for example, throw an IOError, and you want to catch exceptions it raises, but there's something else you want to do if the first operation that is code in try block succeeds , and you don't want to catch an IOError from that operation,then in such situation the else block will be used.
try:
statements # statements that can raise exceptions
except:
statements # statements that will be executed to handle exceptions
else:
statements # statements that will be executed if there is no exception
consider this example:
try:
age=int(input('Enter your age: '))
except:
print ('You have entered an invalid value.')
else:
if age <= 21:
print('You are not allowed to enter, you are too young.')
else:
print('Welcome, you are old enough.')
although there is no proper significance of using else ,because each time when there is no exception we can do our task in try block also.
hope this helps!
'else' runs when for, while loop finished without being interrupted.
To qoute Luciano Ramalho from his book 'Fluent Python',:
I think else is a very poor choice for the keywords in all cases except if. It implies an excluding alternative, like "Run this loop, otherwise to that," but the semantics for else in loops is the opposite: "Run this loop, then do that." This suggests then as a better keyword - which would also make sens in the try context: "Try this, then do that."
Done of nitpicking, why we use try-except-else then? EAFP style coding - at least I believe so.
EAFP - Easier ask Forgiveness Than Permission. Try something first, if error, then do else. This clearly shows coder's intention to catch cases.
This also results better performance if there's few things to trigger error. For example, let's see this extreme case:
import timeit
import random
source = [i for i in range(600000)]
source[random.randint(0, len(source))] = 'bam!'
def EAFP():
numbers = []
for n in source:
try:
result = n + 3
except TypeError:
pass
else:
numbers.append(result)
def LBYL():
numbers = []
for n in source:
if isinstance(n, int):
result = n + 3
numbers.append(result)
print(f"{timeit.timeit(EAFP, number=10):.3f}")
print(f"{timeit.timeit(LBYL, number=10):.3f}")
Results(sec):
2.824
3.393
This would build up if there's more if statements to filter out more possible errors.
And, on readability aspect, lets quote 'Zen of python':
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Multiple nested if is complex than flat try - except - except... - else chain.

Which of these methods is a correct way to return in python?

I have two functions which do the same thing basically but return differently in case of exceptions. Which one is the preferred approach?
Approach 1:
def f1():
try:
data = some_random_function()
return data["success"]
except Exception as error:
print(error)
return "failure"
Approach 2:
def f2():
try:
data = some_random_function()
return data["success"]
except Exception as error:
print(error)
return "failure"
Although both approaches are equivalent, I would recommend approach 1. It makes much clearer that 'failure' is returned only when there is an exception. Someone reading approach 2 may get a first impression that it always returns 'failure'. This is strictly from a clean code perspective.
Although both the approaches work the same way i.e. return data["success"] in case of an exception-free code and return "failure" otherwise, the two approaches differ in the way they convey the information :
A1- Return "failure" in case of an exception
A2- Return "failure" as a default return value.
So, it's my suggestion that you use the second approach as it is more clear and explicit.
As you have a generic catch-all for errors, both approaches are equivalent, because in case of an exception you'll enter the print "failure" branch.
I guess it comes down to matter of taste and maybe future maintainability, i.e. when you add more except branches to handle some errors differently, to choose approach 2.
Its all down to personal preferences. For me, approach 1 is much clearer than two but both are good solutions. I think its more than just individual preference, its more of the code base you are working with. If you are working with a team, look into code with similar structure, see what other's have done. A uniform codebase is much valuable than fancy code here and there.
Also, for languages like JavaScript and python, which have functional scope, I want to put forward a third option:
def f3():
try:
data = some_random_function()
message = "success"
except Exception as error:
print(error)
message = "failure"
return message

What is the elegant/Pythonic way to keep variables in scope, yet also catch exceptions?

I've been using Python for a few months now, and I love it so far. I also like how there is usually a single, "Pythonic" way to handle common programming problems.
In code I've been writing, as I make calls to network functions and have to handle exceptions, I keep running into this template of sorts that I end up writing:
proxyTest = None
try:
proxyTest = isProxyWorking(proxy)
except TimeoutError:
break
if proxyTest:
...
This is my way of declaring proxyTest so that it is in scope when I need to use it, yet also calling the function that will return a value for it inside of the proper exception handling structure. If I declare proxyTest inside of the try block, it will be out of scope for the rest of my program.
I feel like there has to be a more elegant way to handle this, but I'm not sure. Any suggestions?
You have a couple of better options, continue your flow control in the else block:
try:
proxyTest = isProxyWorking(proxy)
except TimeoutError:
break
else:
#proxyTest is guaranteed to be bound here
Or handle the failure case in the except block.
try:
proxyTest = isProxyWorking(proxy)
except TimeoutError:
proxyTest = None
#proxyTest is guaranteed to be bound here
Whichever is better depends on context, I think.
The obvious alternative would be to do the 'false' initialization in the except block:
try:
proxyTest = isProxyWorking(proxy)
except TimeoutError:
proxyTest = None
Whether this is easier/more appropriate than your constructions depends on how complicated the logic is in the middle, though.
I would put the code after
if proxyTest:
in the try block, just after binding proxyTest.

Returning error string from a function in python

I have a class function in Python that either returns a success or a failure, but in case of a failure I want it to send a specific error string back. I have 3 approaches in mind:
Pass in an variable error_msg to the function originally set to None and in case of an error, it gets set to the error string. eg:
if !(foo(self, input, error_msg)):
print "no error"
else:
print error_msg
Return a tuple containing a bool and error_msg from the function.
I raise an exception in case of an error and catch it in the calling code. But since I don't see exceptions being used often in the codebase I am working on, so was not too sure about taking this approach.
What is the Pythonic way of doing this?
Create your own exception and raise that instead:
class MyValidationError(Exception):
pass
def my_function():
if not foo():
raise MyValidationError("Error message")
return 4
You can then call your function as:
try:
result = my_function()
except MyValidationError as exception:
# handle exception here and get error message
print exception.message
This style is called EAFP ("Easier to ask for forgiveness than permission") which means that you write the code as normal, raise exceptions when something goes wrong and handle that later:
This common Python
coding style assumes the existence of valid keys or attributes and
catches exceptions if the assumption proves false. This clean and fast
style is characterized by the presence of many try and except
statements. The technique contrasts with the LBYL style common to many
other languages such as C.
Raise an error:
if foo(self, input, error_msg):
raise SomethingError("You broke it")
And handle it:
try:
something()
except SomethingError as e:
print str(e)
It's the Pythonic approach and the most readable.
Returning a tuple like (12, None) may seem like a good solution, but it's hard to keep track of what each method returns if you're not consistent. Returning two different data types is even worse, as it will probably break code that assumes a constant data type.

How to prevent try catching every possible line in python?

I got many lines in a row which may throw an exception, but no matter what, it should still continue the next line. How to do this without individually try catching every single statement that may throw an exception?
try:
this_may_cause_an_exception()
but_I_still_wanna_run_this()
and_this()
and_also_this()
except Exception, e:
logging.exception('An error maybe occured in one of first occuring functions causing the others not to be executed. Locals: {locals}'.format(locals=locals()))
Let's see above code, all functions may throw exceptions, but it should still execute the next functions no matter if it threw an exception or not. Is there a nice way of doing that?
I dont wanna do this:
try:
this_may_cause_an_exception()
except:
pass
try:
but_I_still_wanna_run_this()
except:
pass
try:
and_this()
except:
pass
try:
and_also_this()
except:
pass
I think code should still continue to run after an exception only if the exception is critical (The computer will burn or the whole system will get messed up, it should stop the whole program, but for many small things also exceptions are thrown such as connection failed etc.)
I normally don't have any problems with exception handling, but in this case I'm using a 3rd party library which easily throws exceptions for small things.
After looking at m4spy's answer, i thought wouldn't it be possible, to have a decorator which will let every line in the function execute even if one of them raises an exception.
Something like this would be cool:
def silent_log_exceptions(func):
#wraps(func)
def _wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
except Exception:
logging.exception('...')
some_special_python_keyword # which causes it to continue executing the next line
return _wrapper
Or something like this:
def silent_log_exceptions(func):
#wraps(func)
def _wrapper(*args, **kwargs):
for line in func(*args, **kwargs):
try:
exec line
except Exception:
logging.exception('...')
return _wrapper
#silent_log_exceptions
def save_tweets():
a = requests.get('http://twitter.com)
x = parse(a)
bla = x * x
for func in [this_may_cause_an_exception,
but_I_still_wanna_run_this,
and_this,
and_also_this]:
try:
func()
except:
pass
There are two things to notice here:
All actions you want to perform have to represented by callables with the same signature (in the example, callables that take no arguments). If they aren't already, wrap them in small functions, lambda expressions, callable classes, etc.
Bare except clauses are a bad idea, but you probably already knew that.
An alternative approach, that is more flexible, is to use a higher-order function like
def logging_exceptions(f, *args, **kwargs):
try:
f(*args, **kwargs)
except Exception as e:
print("Houston, we have a problem: {0}".format(e))
I ran into something similar, and asked a question on SO here. The accepted answer handles logging, and watching for only a specific exception. I ended up with a modified version:
class Suppressor:
def __init__(self, exception_type, l=None):
self._exception_type = exception_type
self.logger = logging.getLogger('Suppressor')
if l:
self.l = l
else:
self.l = {}
def __call__(self, expression):
try:
exec expression in self.l
except self._exception_type as e:
self.logger.debug('Suppressor: suppressed exception %s with content \'%s\'' % (type(self._exception_type), e))
Usable like so:
s = Suppressor(yourError, locals())
s(cmdString)
So you could set up a list of commands and use map with the suppressor to run across all of them.
You can handle such a task with a decorator:
import logging
from functools import wraps
def log_ex(func):
#wraps(func)
def _wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
except Exception:
logging.exception('...')
return _wrapper
#log_ex
def this_may_cause_an_exception():
print 'this_may_cause_an_exception'
raise RuntimeError()
#log_ex
def but_i_wanna_run_this():
print 'but_i_wanna_run_this'
def test():
this_may_cause_an_exception()
but_i_wanna_run_this()
Calling the test function will look like (which will show that both functions were executed):
>>> test()
this_may_cause_an_exception
ERROR:root:...
Traceback (most recent call last):
File "<stdin>", line 5, in _wrapper
File "<stdin>", line 4, in my_func
RuntimeError
but_i_wanna_run_this
Sometimes, when language misses to support your elegant way of expressing an idea because language development literally failed the last decades, you can only rely on the fact that Python is still a dynamical language which supports the exec statement, which makes the following possible:
code="""
for i in range(Square_Size):
Square[i,i] #= 1
Square[i+1,i] #= 2
#dowhatever()
"""
This new operator makes code more pythonic and elegant since you don't need to specify additional if-statemens that guarantee that the index stays in bound or the function does succeed which is totally irrelevant to what we want to express (it just shouldn't stop) here (note: while safe indexing would be possible by creating a class based on the list class, this operator works whenever there should be a try catch) , in Lisp it would be easy to define it in a Lispy way, but it seams to be impossible to define it in an elegant way in Python, but still, here is the little preparser which will make it possible:
exec "\n".join([o+"try: "+z.replace("#","")+"\n"+o+"except: pass" if "#" in z else z for z in code.split("\n") for o in ["".join([h for h in z if h==" "])]]) #new <- hackish operator which wraps try catch into line
The result, assuming that Square was 4x4 and contained only zeros:
[1 0 0 0]
[2 1 0 0]
[0 2 1 0]
[0 0 2 1]
Relevant: The Sage / Sagemath CAS uses a preparse-function
which transforms code before it reaches the Python interpreter.
A monkey-patch for that function would be:
def new_preparse(code,*args, **kwargs):
code="\n".join([o+"try: "+z.replace("#","")+"\n"+o+"except: pass" if "#" in z else z for z in code.split("\n") for o in ["".join([h for h in z if h==" "])]])
return preparse(code)
sage.misc.preparser.preparse=new_preparse
Apart from the answers provided, I think its worth to note that one-line try-except statements have been proposed - see the related PEP 463 with the unfortunate rejection notice:
""" I want to reject this PEP. I think the proposed syntax is acceptable given the
desired semantics, although it's still a bit jarring. It's probably no worse than the
colon used with lambda (which echoes the colon used in a def just like the colon here
echoes the one in a try/except) and definitely better than the alternatives listed.
But the thing I can't get behind are the motivation and rationale. I don't think that
e.g. dict.get() would be unnecessary once we have except expressions, and I disagree
with the position that EAFP is better than LBYL, or "generally recommended" by Python.
(Where do you get that? From the same sources that are so obsessed with DRY they'd rather
introduce a higher-order-function than repeat one line of code? :-)
This is probably the most you can get out of me as far as a pronouncement. Given that
the language summit is coming up I'd be happy to dive deeper in my reasons for rejecting
it there (if there's demand).
I do think that (apart from never explaining those dreadful acronyms :-) this was a
well-written and well-researched PEP, and I think you've done a great job moderating the
discussion, collecting objections, reviewing alternatives, and everything else that is
required to turn a heated debate into a PEP. Well done Chris (and everyone who
helped), and good luck with your next PEP! """
try:
this_may_cause_an_exception()
except:
logging.exception('An error occured')
finally:
but_I_still_wanna_run_this()
and_this()
and_also_this()
You can use the finally block of exception handling. It is actually meant for cleanup code though.
EDIT:
I see you said all of the functions can throw exceptions, in which case larsmans' answer is about the cleanest I can think of to catch exception for each function call.

Categories

Resources