So I want to be efficient in making code in python, and I am doing something like this:
try:
#Code A
except:
#Code A
try:
#Code B
except:
#Code B
try:
#Code B
except:
#Code B
But I want to link all of them to one except block so I can use an else statement to catch em' all! (Reference intended).
So could I do something like the following?
try:
#Code A
try:
#Code B
except:
#Code C
else:
#Code D
I have tried the code, but to my self findings and limited questions that are 'similar' all I get is: Error: invalid syntax "try:". Is there anything I can do about this?
You actually don't need those extra trys at all. Whenever there's an exception raised inside the try block, all code starting there until the end of the block is skipped and the control jumps immediately to the matching except block. And as well, the else block is executed when the try block reachs its end normally. This way you don't need multiple try blocks - just concatenate them into one and you'll achieve your aim.
No you can't have multiple try block associated with only one except block. but you can have muliple except block releated to only one try block.
every try block need except block if you didn't provide one you will have an exception.
example of mulitple except block releated to one try block :-
try:
# do something
pass
except ValueError:
# handle ValueError exception
pass
except (TypeError, ZeroDivisionError):
# handle multiple exceptions
# TypeError and ZeroDivisionError
pass
except:
# handle all other exceptions
pass
suppose you perform some operation in try block and you encountered a problem then first except block will take the control if it can't handle the exception then the below except block will handle it and so on......
Note: if the first except block can handle the exception the next except block does not execute or will not come in action.
It is always good practice to have more generic except block for a specific exception type.
a single try statement with multiple except block
try:
#put your risky code
# put another risky code
pass
# multiple exception block will help to catch exact exception and can perform
# operation
except KeyError:
pass
except IOError:
pass
except ValueError:
pass
except Exception:
pass
else:
pass
Related
Is there a functional difference between the exception handling in code blocks 1,2,3? I want to print different messages based on the type error for example including the error code if psycopg2 error. I have read that nested try except blocks are good practice. I'm using psycopg2 as an example.
# code block 1
def my_func(fun_arg):
try:
# ... some stuff
except psycopg2.Error as error:
print(f"Error while inserting data to PostgreSQL {type(error).__name__} {error.pgcode} {error.pgerror}")
except Exception as error:
print(f'error in my_func {type(error).__name__} {error.args}')
# code block 2
def my_func(fun_arg):
try:
# ... some stuff
try:
# ... some stuff
except psycopg2.Error as error:
print(f"Error while inserting data to PostgreSQL {type(error).__name__} {error.pgcode} {error.pgerror}")
except Exception as error:
print(f'error in my_func {type(error).__name__} {error.args}')
# code block 3
def my_func(fun_arg):
try:
# ... some stuff
except (psycopg2.Error, Exception) as error:
if (type(error).__name__ in (
'DatabaseError', 'OperationalError', 'NotSupportedError',
'ProgrammingError', 'DataError','IntegrityError',))
print(f"Error while inserting data to PostgreSQL {type(error).__name__} {error.pgcode} {error.pgerror}")
else:
print(f'error in my_func {type(error).__name__} {error.args}')
In your case, there is no functional difference. In such a case, you may follow the Zen of Python to choose the one that fits best. There are a lot of ways to interpret it but I would choose block number 1 as it is the simplest, the flattest, and the most readable one.
Block number one is the preferred one for the reasons above I'd say.
Block number two is needed when all the branches of the inner try can raise the same exception and the handler of the exception is also the same. E.g.:
try:
try:
store_to_db(value)
except ValueError:
store_to_db(fallback)
except DbError:
log_error()
Block number three is just a more complicated and more difficult-to-read alternative to block number one. I cannot imagine a practical use case for it except that there is a shared code for both exceptions. E.g.:
try:
do_something()
except (DatabaseError, OperationalError, KeyError) as error:
data = collect_some_data()
if type(error).__name__ in ('DatabaseError', 'OperationalError'):
print(f"Error while inserting data to PostgreSQL {data}")
else:
print(f'error in my_func {data}')
Although isinstance is probably preferred over type(error).__name__ ==. And I would still argue that it is better to split it into multiple except clauses and repeat the call to collect_some_data but it is a matter of personal preferences.
Another thing to take into account is that it is generally preferred to "limit the try clause to the absolute minimum amount of code necessary as it avoids masking bugs" [PEP 8]. This is another reason to avoid nested try whenever possible.
I think either of the first two options are fine.
Personally I find I think the first is easier to read for a short simple function although if my_func was larger and more complex with nesting then I would opt for the second option as it makes it clear where exactly where sycopg2.Error may be raised.
The wouldn't use the third option. If you want to catch multiple exceptions use this syntax:
except (RuntimeError, TypeError, NameError):
pass
In Python's try, except blocks, why does else need to exist if I can just use an except: without a specifier?
It seems like your understanding of how try, except, else, and finally is off.
Here's a summary of how they all work together, from looking at https://docs.python.org/2/tutorial/errors.html:
try:
#Try something that might raise an exception
except <exception specifier>:
#Code here will only run if the exception that came up was the one specified
except:
#Except clause without specifier will catch all exceptions
else:
#Executed if try clause doesn't raise exception
#You can only have this else here if you also have except blocks
finally:
#Runs no matter what
In what I have written, NoResultException can be raised either in my try block or my except UnexpectedAlertPresentException block. I would like to go to the except NoResultException block in either case, but it only does this if NoResultException is raised in the try block. This is approximately what I have now:
try:
# do things
except UnexpectedAlertPresentException:
# do other things, including possibly raise NoResultException
except NoResultException:
# handle exception
I could change it to something like this:
try:
# do things
except UnexpectedAlertPresentException:
try:
# do other things, including possibly raise NoResultException
except NoResultException:
# handle exception
except NoResultException:
# handle exception
to handle NoResultException, but I'm trying to avoid repeating myself. Is there any better way to do this?
try:
try:
# do things
except UnexpectedAlertPresentException:
# do other things, including possibly raise NoResultException
except NoResultException:
# handle exception
Try not to go overboard with the exception-handling control flow. The logic can get really hard to reason about, and the indentation can get really deep.
I want to know what is the most elegant way of writing try..except statements in python. Assume I have this code:
with open(sys.argv[1]) as f:
for line in f:
try:
do_1(line)
except:
pass
try:
do_2(line)
except:
pass
try:
do_3(line)
except:
pass
...
...
What is the best way of writing this? My actions are sequential. However, if do_1 fails I still want to perform do_2. If all of them are in one try..except block, then if do_1 fails, I will never reach do_2. Is this the right way, or can I have one except for all of d0_i actions?
It's simple enough to write this as a loop:
for action in [do_1, do_2, do_3, ...]:
try:
action(line)
except AppropriateExceptionType:
pass
I would factor out the common code which is your try/except statements. Something like:
def run_safely(f, *args):
try:
f(*args)
except SpecificException:
# handle appropriately here
pass
with open(sys.argv[1]) as f:
for line in f:
run_safely(do_1, line)
run_safely(do_2, line)
run_safely(do_3, line)
Essentially, you need each do_<Step> function to run inside the finally block of the previous one, like so:
try:
do_1(line)
except:
# Handle failure
pass
finally:
# Run regardless
try:
do_2(line)
except:
# Handle failure
finally:
# Run regardless
try:
do_3(line)
...
This chains the functions together through the finally block. Notice that in the event of an exception at any step, the exception is handled before starting the next step, which is guaranteed to run regardless of whether an exception is generated or not.
Since your functions all have the same shape (taking the same number and type of arguments), you can abstract out this pattern into a function, like tryChain below:
def tryChain(functions, *sharedArgs)
f = functions.pop()
try:
f(*sharedArgs)
finally:
tryChain(functions)
try:
tryChain([do_1, do_2, ...], line, arg2, ...)
except SpecificException:
# Handle exception here, which may be propagated from any of the actions
pass
Note that in this case, only the last exception is thrown back to the caller; the others are hidden. (You could handle the exceptions inside tryChain as well, with an except block inserted there; or, you could pass in an error handler for each step; or a map from exception types to the appropriate handler, and re-throw the error if none of them matches — but at that point, you're practically reinventing exception handling.)
I have this kind of code:
try:
return make_success_result()
except FirstException:
handle_first_exception()
return make_error_result()
except SecondException:
handle_second_exception()
return make_error_result()
And I'm wondering is there any way I can achieve this:
try:
# do something
except Error1:
# do Error1 specific handling
except Error2:
# do Error2 specific handling
else:
# do this if there was no exception
????:
# ALSO do this if there was ANY of the listed exceptions (e.g. some common error handling)
So the code is executed in one of following sequences:
try > else > finally
try > except > ???? > finally
EDIT: my point here is that ???? block should execute right after ANY of the except blocks, meaning that it's an addition to error handling, not a substitution.
What I would do in that case is to set a boolean when you get an exception, like so:
got_exception = False
try:
# do something
except Error1:
# do Error1 specific handling
got_exception = True
except Error2:
# do Error2 specific handling
got_exception = True
else:
# If there was no exception
finally:
if got_exception:
# ALSO do this if there was ANY exception (e.g. some common error handling)
This should fit your needs, which is IMO the cleanest way of combining all of the solutions which have been presented into the most readable code structure that's going to be the easiest to debug.
You can actually do this:
try:
print 'try'
# 1/0
# {}[1]
# {}.a
except AttributeError, KeyError: # only handle these exceptions..
try:
raise # re-raise the exception so we can add a finally-clause executing iff there was an exception.
except AttributeError:
print 'attrerr'
# raise ... # any raises here will also execute 'common'
except KeyError:
print 'keyerror'
finally: # update 0: you wanted the common code after the exceptions..
print "common"
else:
print 'no exception'
but it is horrid and I would not suggest that you do without copious amounts of comments describing why..
UPDATE: you don't need to catch anything but the interesting exceptions in the inner try-block. Code updated.
UPDATE2: per OP's clarification, common should just be executed when an interesting exception is thrown. Code updated. #MattTaylor's version is definitely the way to go ;-)
Yes, exception handling in python includes both an else and a finally clause. You can do this:
try:
# do something
except Error1:
# do Error1 specific handling
except Error2:
# do Error2 specific handling
else:
# do this if there was no exception
finally:
# Do this in any case!
The python docs mention these blocks, even though it doesn't show the full example you need.
EDIT:
I see that you do not ask specifically for the clean-up in the general case. Python docs put it this way:
The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances.
Note that the finally will run whether there was an exception or not. Combined with the else block, you should still be able to do what you want.
You could trap all errors and check for its type in the error handling code like this:
try:
# do something
except Exception as e:
if isinstance(e, Error1):
# do Error1 specific handling
elif isinstance(e, Error2):
# do Error2 specific handling
else:
# do non-Error1/Error2 handling
# ALSO do this if there was ANY exception (e.g. some common error handling)
else:
# do this if there was no exception