Failing fast by raising an exception with a custom message This is a script that utilizes lazy exception throwing. What I do is decorate a function that might throw an exception to throw an exception with a formatted string. 

from functools import wraps

def on_fail(message):
    def on_fail_dec(func):
        @wraps(func)
        def on_fail_wrapper(*args, **kw):
            ret = None
            success = True
            message_addon = ""
            try:
                ret = func(*args, **kw)
            except Exception as e:
                success = False
                message_addon = str(e)
            # raise Exception if failed
            if not success:
                raise Exception("{0}\nBecause: {1}".format(message, message_addon))

            return ret
        return on_fail_wrapper
    return on_fail_dec

# Usage :

@on_fail("Division Failed")
def divide(a, b):
    return a / b

test_cases = [(1, 2), (20, 5), (3, 0)]

for a,b in test_cases:
    print("Trying to divide {0} from {1}".format(a, b))
    print(divide(a, b))


Output:




Trying to divide 1 from 2
0.5
Trying to divide 20 from 5
4.0
Trying to divide 3 from 0
Traceback (most recent call last):
  File "&lt;string&gt;", line 30, in &lt;module&gt;
  File "&lt;string&gt;", line 16, in on_fail_wrapper
Exception: Division Failed
Because: division by zero
Instead of handling just "Division Failed" you should extend your function to handle any possible error, plus it's better if you pass the exception object along with the message to the decorator as well, by doing this you'll know exactly which error you're going to handle because a except Exception will handle any Exception not just what we actually intended it to.
Second there's no need to use flag variables here, we can simply return the return value from the try-block and in case of exception we re-raise the exception after it is caught.


Code:

from functools import wraps


def on_fail(exception, message):
    def on_fail_dec(func):
        @wraps(func)
        def on_fail_wrapper(*args, **kw):
            message_addon = ""
            try:
                # do something before
                ret = func(*args, **kw)
                # do something after
                return ret
            except exception as e:
               message_addon = str(e)
            raise exception("{0}\nBecause: {1}".format(message, message_addon))
        return on_fail_wrapper
    return on_fail_dec


@on_fail(ZeroDivisionError, "Division Failed")
def divide(a, b):
    return a / b

test_cases = [(1, 2), (20, 5), (3, 0)]

for a, b in test_cases:
    print("Trying to divide {0} from {1}".format(a, b))
    print(divide(a, b))


Note that in above code I didn't use something simple like:

except exception as e:
    raise exception("{0}\nBecause: {1}".format(message, e))


That's because Python 3 introduced something called exception chaining, which means if an exception occurs while handling another exception then the previous exception still remains available to us(Read PEP 3134 - PEP 3134 -- Exception Chaining and Embedded Tracebacks), but this is not useful here as it will end up raising something like:

Trying to divide 3 from 0
Traceback (most recent call last):
  File "/home/ashwini/py/so.py", line 10, in on_fail_wrapper
    ret = func(*args, **kw)
  File "/home/ashwini/py/so.py", line 20, in divide
    return a / b
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/ashwini/py/so.py", line 26, in &lt;module&gt;
    print(divide(a, b))
  File "/home/ashwini/py/so.py", line 13, in on_fail_wrapper
    raise exception("{0}\nBecause: {1}".format(message, e))
ZeroDivisionError: Division Failed
Because: division by zero