1

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
3
  • The third attempt is different from the first two, it will only handle creation_errors that happen in the # attempt to write here block, exceptions thrown in the # create new file using custom API block will not be caught by the code in your third attempt. – Jasmijn Oct 31 '20 at 7:31
  • Python is strange to me given how liberally it throws exceptions for things I don't consider that exceptional, but I would still be inclined in many cases to catch as generally, not specifically, as possible in places that perform actual error recovery. The main reason I'd offer that is that unless it's a library that's very well-documented about what a function may throw and never extends that list in the future, it may be difficult to correctly anticipate all possible exceptions that could be thrown in a deeply recursive calling case, not to mention that it might change if one of [...] – user377672 Nov 2 '20 at 6:32
  • [...] your colleagues make changes to the implementation of one of a possibly large list of functions that are directly or indirectly called in the try block. – user377672 Nov 2 '20 at 6:32
3

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.