Question

Should the exception blocks in a try-except sequence be specific only to those exceptions which may originate from the try? Or can they be inclusive of exceptions that may arise from handling the original exception caught?

I currently have a function that has a try-except block to write some data to file. When a specific sizing exception is met (meaning the file is at max size), the write fails (as it should), the exception is caught and a new file is attempted to be create; if successful, the write attempt occurs again otherwise and exception is caught for failure to create.

This construct looks as follows (pseudo):

file_error = False
while not file_error:

    written = False
    while not written and not file_error:
        try:
            # attempt to write here
        except size_error:
            try:
                # create new file using custom API
            except creation_error:
                file_error = True
        else:
            written = True

I didn't like how this was nested, so I took out the nesting:

file_error = False
while not file_error:

    written = False
    while not written and not file_error:
        size_error_caught = False
        try:
            # attempt to write here
        except size_error:
            size_error_caught = True
        else:
            written = True

        if size_error_caught:
            try:
                # create new file using custom API
            except creation_error:
                file_error = True

But then I thought, why bother nesting or adding another boolean variable, why not just try to do the work in the originally caught exception and add the previously nested exception to the same scope?:

file_error = False
while not file_error:

    written = False
    while not written and not file_error:
        try:
            # attempt to write here
        except size_error:
            # create new file using custom API
        except creation_error:
            file_error = True
        else:
            written = True
Was it helpful?

Solution

Should the exception blocks in a try-except sequence be specific only to those exceptions which may originate from the try? Or can they be inclusive of exceptions that may arise from handling the original exception caught?

This depends a bit on the language in question, but most languages, including Python, do not look at the other except clauses when a new exception is thrown while in an except block.

The usual specification for exception handling is that when an exception is thrown, then the runtime looks up through the call-stack for try blocks and tries to find one with an except clause that matches the thrown exception. Then the execution jumps out of the try block into the except block (doing whatever cleanup is required by the language specification).

This means that once you are within an except block, the try block from which the exception originated is no longer active and thus the sibling except blocks will not be considered for handling a new exception.

This means that in your third example, the creation_error will not be caught if the exception gets thrown while handling a size_error.

You could write the construct like this:

file_error = False
try:
    while True: # To keep the same semantics: Keep writing until creating a new file fails.
        written = False
        while not written:
            try:
                # attempt to write here
            except size_error:
                # create new file using custom API
        else:
            written = True
except creation_error:
     file_error = True

This still has the nested try blocks, but it makes it a bit clearer that you retry writing in a new file after a size_error and that the creation_error is a problem that affects a larger part of the code.

Licensed under: CC-BY-SA with attribution
scroll top