Search code examples
pythontry-except

Can an exception occur in a try/except statement without skipping the rest of the try clause?


Suppose the following code:

try:
    code_a
    code_b
    code_c
except:
    pass

If an error occurs in code_b, then it will be caught by the except and only code_a will have run. Is there a way to ensure code_c runs as well?

I imagine:

try: 
    code_a
except: 
    pass
try: 
    code_b
except: 
    pass
try: 
    code_c
except: 
    pass

is not the right way to go about it.


Solution

  • The short answer to your title question is No. The rest of the try: block will not execute after an exception.

    As you note, you can put code_a, code_b and code_c in their own try: blocks and handle errors separately.

    You asked if code_c could run even if code_b raised an exception.

    Option 1

    Put code_c outside the try: block entirely:

    try:
        code_a
        code_b
    except:
        pass
    code_c
    

    But take care. code_c won't definitely execute. it depends what's in the except: block. Consider the following example:

    try:
        code_a
        code_b
    except:
        return False
    code_c
    return True
    

    If code_a or code_b raise an exception, code_c will not execute.

    Option 2

    Use a finally: block:

    try:
        code_a
        code_b
    except:
        return False
    finally:
        code_c
    return True
    

    If code_c is in a finally: block it is guaranteed to execute whether or not there is an exception.

    If there is no exception, code_c executes after code_a and code_b.

    If there is an exception, return False will work as expected BUT code_c will squeeze in and execute just before the function returns. This is because it is guaranteed to execute.

    Complete Example

    def ham():
        print('Ham please')
    
    
    def eggs():
        print('Eggs please')
        raise NoEggsException
    
    
    class NoEggsException(Exception):
        pass
    
    
    def spam():
        print('Spam Spam Spam Spam Spam!')
    
    
    def order():
        try:
            ham()
            eggs()
        except NoEggsException:
            print('    ...no eggs :(')
            return False
        finally:
            spam()
        return True
    
    
    if __name__ == '__main__':
        order_result = order()
        print(f'Order complete: {order_result}')
    

    When run as written, eggs() raises an exception. The result is as follows:

    Ham please
    Eggs please
        ...no eggs :(
    Spam Spam Spam Spam Spam!
    Order complete: False
    

    Note that spam() (in the finally: block) is executed even though there is a return False in the except: block.

    Here is what happens when raise NoEggsException is commented out or removed:

    Ham please
    Eggs please
    Spam Spam Spam Spam Spam!
    Order complete: True
    

    Note that you get spam (and more spam) in your order either way.