How to write multiple try statements in one block in python? - python

I want to do:
try:
do()
except:
do2()
except:
do3()
except:
do4()
If do() fails, execute do2(), if do2() fails too, exceute do3() and so on.
best Regards

If you really don't care about the exceptions, you could loop over cases until you succeed:
for fn in (do, do2, do3, do4):
try:
fn()
break
except:
continue
This at least avoids having to indent once for every case. If the different functions need different arguments you can use functools.partial to 'prime' them before the loop.

I'd write a quick wrapper function first() for this.
usage: value = first([f1, f2, f3, ..., fn], default='All failed')
#!/usr/bin/env
def first(flist, default=None):
""" Try each function in `flist` until one does not throw an exception, and
return the return value of that function. If all functions throw exceptions,
return `default`
Args:
flist - list of functions to try
default - value to return if all functions fail
Returns:
return value of first function that does not throw exception, or
`default` if all throw exceptions.
TODO: Also accept a list of (f, (exceptions)) tuples, where f is the
function as above and (exceptions) is a tuple of exceptions that f should
expect. This allows you to still re-raise unexpected exceptions.
"""
for f in flist:
try:
return f()
except:
continue
else:
return default
# Testing.
def f():
raise TypeError
def g():
raise IndexError
def h():
return 1
# We skip two exception-throwing functions and return value of the last.
assert first([f, g, h]) == 1
assert first([f, g, f], default='monty') == 'monty'

It seems like a really odd thing to want to do, but I would probably loop over the functions and break out when there were no exception raised:
for func in [do, do2, do3]:
try:
func()
except Exception:
pass
else:
break

Here is the simplest way I found, just embed the try under the previous except.
try:
do()
except:
try:
do2()
except:
do3()

You should specify the type of the exception you are trying to catch each time.
try:
do()
except TypeError: #for example first one - TypeError
do_2()
except KeyError: #for example second one - KeyError
do_3()
and so on.

if you want multiple try statments you can do it like this, including the except statement. Extract (refactor) your statements. And use the magic of and and or to decide when to short-circuit.
def a():
try: # a code
except: pass # or raise
else: return True
def b():
try: # b code
except: pass # or raise
else: return True
def c():
try: # c code
except: pass # or raise
else: return True
def d():
try: # d code
except: pass # or raise
else: return True
def main():
try:
a() and b() or c() or d()
except:
pass

import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise

Related

Python try/except depending on variable

i need continue in program after except when variable is True but when variable is False need exit program.
I think there will be if else but I'm not sure how to use it.
for examlpe:
var = True
try:
print 2/0
except:
exit(1)
... continue executing
var = False
try:
print 2/0
except:
exit(1)
... exit
Thanks for comments.
This ought to do the trick, by the way you should probably use raise.
var = True
try:
print 2/0
except:
if not var:
# I recommend using raise, as it would show you the error
exit(1)
If you have a number of except groups which will need to use the var try this
Note that you can expand myexcept using decorators or closures in order to set up additional processing within the exception as well. Since a function is an object, you can use a different specialfunc() for every except: that you write. You can set up the myexcept to handle calls to specialfunc() with arguments as well using the variable arguments process as shown below
def specialfunc1():
# put the special function code here
def specialfunc2(arg1):
# put the processing here
def specialfunc3(arg1, arg2):
# put the processing here
def myexcept(var, e, specialfunc, *args)
print 'Exception caught for ', e
if var:
specialfunc(*args)
else:
raise # This raises the current exception to force an exit
try:
# code you are testing
2/0
except Error1, e:
myexcept(var, e, specialfunc1)
except Error2, e:
myexcept(var, e, specialfunc2(arg1))
except Error3, e:
myexcept(var, e, specialfunc3(arg1, arg2))
except: # this default forces the regular exception handler
# remaining code

Clearing concepts on the exception

Let's say I have a function.
def foo(data):
if data:
return data[0]
else:
raise ValueError('data is empty')
def main_foo(..):
ele = foo(data)
Now, i want to catch that exception as one of my friends commented
Please re-raise the errors at main_foo
So does that mean I do something like:
def main_foo( .. ):
try:
ele = foo(data)
except ValueError:
logger.log("exception caught")
If you want to log the occurrence of an exception in main_foo, but let some other function actually handle the exception, do this:
def main_foo():
try:
ele = foo(data)
except ValueError:
logger.log("Exception caught")
raise
This will raise the same exception for the caller of main_foo to deal with.

Is this function correct?

Is it correct to call that function in some exceptions ?
Is that process correct ? Is it better to process each exceptions ?
def close_all():
try:
ftp.close()
except:
pass
try:
tar.close()
except:
pass
try:
savelist.close()
except:
pass
try:
os.remove(tarname)
except:
pass
exit()
Thanks in advance.
I think you should handle each exception one by one. This will shorten your code. First of all note all the exceptions that ftp.close() and other methods will raise. Then handle them one by one.
Example:
>>> a = 5 # a is an integer
>>> b = "Bingo" # b is a string
>>>
>>> def add_five():
try:
c + 5 # c is not defined. NameError exception is raised
except NameError:
b + 5 # b is a string. TypeError exception is raised
except TypeError:
a + 5 # a is int. No exception is raised
except:
# This last except clause is just in case you forgot to handle any exception
pass
>>>

Multiple try codes in one block

I have a problem with my code in the try block.
To make it easy this is my code:
try:
code a
code b #if b fails, it should ignore, and go to c.
code c #if c fails, go to d
code d
except:
pass
Is something like this possible?
You'll have to make this separate try blocks:
try:
code a
except ExplicitException:
pass
try:
code b
except ExplicitException:
try:
code c
except ExplicitException:
try:
code d
except ExplicitException:
pass
This assumes you want to run code c only if code b failed.
If you need to run code c regardless, you need to put the try blocks one after the other:
try:
code a
except ExplicitException:
pass
try:
code b
except ExplicitException:
pass
try:
code c
except ExplicitException:
pass
try:
code d
except ExplicitException:
pass
I'm using except ExplicitException here because it is never a good practice to blindly ignore all exceptions. You'll be ignoring MemoryError, KeyboardInterrupt and SystemExit as well otherwise, which you normally do not want to ignore or intercept without some kind of re-raise or conscious reason for handling those.
You can use fuckit module.
Wrap your code in a function with #fuckit decorator:
#fuckit
def func():
code a
code b #if b fails, it should ignore, and go to c.
code c #if c fails, go to d
code d
Extract (refactor) your statements. And use the magic of and and or to decide when to short-circuit.
def a():
try: # a code
except: pass # or raise
else: return True
def b():
try: # b code
except: pass # or raise
else: return True
def c():
try: # c code
except: pass # or raise
else: return True
def d():
try: # d code
except: pass # or raise
else: return True
def main():
try:
a() and b() or c() or d()
except:
pass
If you don't want to chain (a huge number of) try-except clauses, you may try your codes in a loop and break upon 1st success.
Example with codes which can be put into functions:
for code in (
lambda: a / b,
lambda: a / (b + 1),
lambda: a / (b + 2),
):
try: print(code())
except Exception as ev: continue
break
else:
print("it failed: %s" % ev)
Example with arbitrary codes (statements) directly in the current scope:
for i in 2, 1, 0:
try:
if i == 2: print(a / b)
elif i == 1: print(a / (b + 1))
elif i == 0: print(a / (b + 2))
break
except Exception as ev:
if i:
continue
print("it failed: %s" % ev)
Lets say each code is a function and its already written then the following can be used to iter through your coding list and exit the for-loop when a function is executed without error using the "break".
def a(): code a
def b(): code b
def c(): code c
def d(): code d
for func in [a, b, c, d]: # change list order to change execution order.
try:
func()
break
except Exception as err:
print (err)
continue
I used "Exception " here so you can see any error printed. Turn-off the print if you know what to expect and you're not caring (e.g. in case the code returns two or three list items (i,j = msg.split('.')).
You could try a for loop
for func,args,kwargs in zip([a,b,c,d],
[args_a,args_b,args_c,args_d],
[kw_a,kw_b,kw_c,kw_d]):
try:
func(*args, **kwargs)
break
except:
pass
This way you can loop as many functions as you want without making the code look ugly
I use a different way, with a new variable:
continue_execution = True
try:
command1
continue_execution = False
except:
pass
if continue_execution:
try:
command2
except:
command3
to add more commands you just have to add more expressions like this:
try:
commandn
continue_execution = False
except:
pass
I ran into this problem, but then it was doing the things in a loop which turned it into a simple case of issueing the continue command if successful. I think one could reuse that technique if not in a loop, at least in some cases:
while True:
try:
code_a
break
except:
pass
try:
code_b
break
except:
pass
etc
raise NothingSuccessfulError
Like Elazar suggested:
"I think a decorator would fit here."
# decorator
def test(func):
def inner(*args, **kwargs):
try:
func(*args, **kwargs)
except: pass
return inner
# code blocks as functions
#test
def code_a(x):
print(1/x)
#test
def code_b(x):
print(1/x)
#test
def code_c(x):
print(1/x)
#test
def code_d(x):
print(1/x)
# call functions
code_a(0)
code_b(1)
code_c(0)
code_c(4)
output:
1.0
0.25

Try...Except on multiple, independent statements, executing as many as possible

I want to execute several functions, gather their exceptions (if there are any), and raise a compound exception, calling as many of the functions as possible without breaking after one exception. For example, say I have
def f():
do_one()
do_two()
do_three()
The do_i functions don't depend on each other's status. The most obvious way to do what I want is this:
def f():
errors = []
for do_i in [do_one, do_two, do_three]:
try:
do_i()
except Exception as e:
errors.append(e)
if errors:
raise Exception(';'.join(errors))
or slightly better:
def catch_error(arr, f, *args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as e:
arr.append(e)
return None
def f():
errors = []
for do_i in [do_one, do_two, do_three]:
catch_error(errors, do_i)
if errors:
raise Exception(';'.join(errors))
but this is still ugly. Is there a Pythonic way to do this that I'm missing, maybe with clever use of a with statement?
Edit: In a dream world Python would have this:
errors = []
awesome_block(errors):
do_one()
do_two()
do_three()
return 'yes!' if not errors else ';'.join(map(str, errors))
You could rewrite your function into a contextmanager, which does simplify your code a bit. I've maintained your convention of passing a list, though this yields the internal list, so you can use it later.
from contextlib import contextmanager
#contextmanager
def catch_errors(error_list=None):
error_list = error_list if error_list is not None else []
try:
yield error_list
except Exception as e:
error_list.append(e)
error_list = []
with catch_errors(error_list):
raise Exception("First exception")
with catch_errors(error_list):
raise ValueError("Second exception")
if error_list:
raise Exception(";".join(map(repr, error_list)))
I think repr is more useful than str here. #contextmanager allows usage in a with statement while you only have to write the function as a generator.
If you don't pass a list to the generator, then you need to keep track of the returned list.
with catch_errors() as errors1:
raise Exception("First exception")
print errors1 # Exception("First exception",)

Categories

Resources