3

Lets say we have the following code:

print("...")
might_throw_type_error()
print("...")
might_throw_index_error()

If we want to handle the exceptions that those functions might arise what is the preferred way:


Full split of "business" code and error handling

try:
    print("...")
    might_throw_type_error()
    print("...")
    might_throw_index_error()
except IndexError:
    # index error handling logic
    raise
except TypeError:
    # index error handling logic
    raise

Split of logic and error handling but try starting at the first statement that might raise

print("...")
try:
    might_throw_type_error()
    print("...")
    might_throw_index_error()
except IndexError:
    # index error handling logic
    raise
except TypeError:
    # index error handling logic
    raise

Exception handling should only wrap statements we expect to raise

print("...")
try:
    might_throw_type_error()
except TypeError:
    # index error handling logic
    raise
print("...")
try:
    might_throw_index_error()
except IndexError:
    # index error handling logic
    raise

Note that if we capture the exception we don't want to continue

Mario Corchero
  • 5,257
  • 5
  • 33
  • 59

2 Answers2

2

It definitely depends on what exactly you want to achieve - consider that if you will use the #1 approach if something will go wrong with the first might_throw_index_error the following print and second might_throw_index_error will never been executed.

On the second hand the last one guarantees you that at least the secon print will always fire.

Every of these ways are good but it depends on what you want to do with your application flow.

m.antkowicz
  • 13,268
  • 18
  • 37
  • sorry, forgot to add that. the exception handling just logs and reraise (so the logic is the same). Let me update the question – Mario Corchero Oct 25 '16 at 10:36
  • The answer is still the same - only important is if you want to try trigger second method in case of fail on first - if not there's no reason to not put them inside one `try-except` – m.antkowicz Oct 25 '16 at 10:39
  • So you don't agree with the sentence "Exception handling should only wrap statements we expect to raise". The argument for this was that it makes clearer for the reader what function raises the specific type of exception – Mario Corchero Oct 25 '16 at 10:43
  • If you see 100 `try-except` blocks one after another more readable that one with multiple `except` that's your choice. If I have a process that can be broken in multiple places but definitely should be stopped in case of any I'm always using one `try-except` block. – m.antkowicz Oct 25 '16 at 10:46
-1

create a decorator and add that decorator to each of your function definition. Check A guide to Python's function decorators for detailed information. For example, your decorator should be like:

def wrap_error(func):
    def func_wrapper(*args, **kwargs):
        try:
           return func(*args, **kwargs)
        except ValueError:
           # Some logic here
        except IndexError:
           # some logic here
    return func_wrapper

Now add this decorator with your function definition as:

@wrap_error
def function1():
    some code

Now you may simply make a call to the function as:

function1()  # No need to handle the errors explicitly

without worrying about explicitly handling the errors, every time it is called.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • "Explicit is better than implicit" and wrapping exceptions in a decorator is as frighteningly implicit as I've seen. – msw Oct 25 '16 at 11:37
  • Depends on requirement to requirement. My view on this is little different. As per me this is better. Say you want to write entries into the log file. Later the requirement got changed and now you also need to send the email. Will you go and modify the code every where you handled the exception? It provides a cleaner way. Your function code isolated from nasty try/except, your main function is clean, and decorator sits in the corner managing all the nasty tasks – Moinuddin Quadri Oct 25 '16 at 12:09