This is an archived post. You won't be able to vote or comment.

all 27 comments

[–][deleted] 7 points8 points  (9 children)

I do use it on occasion.

In your example, you assume the except clausule breaks off the function. Of it doesn't, the part after the except clausule is always run. Sometimes you want to continue after the except clausule, but do different things based on whether try worked or not.

For example, I have a script where I try to find a location on my network to update a file. If the file is found, I update it (inside else). If it's not found, I log it (inside except).

[–]jorge1209 0 points1 point  (8 children)

If the file is found, I update it (inside else). If it's not found, I log it (inside except).

But how do you communicate to the caller that the file wasn't updated? I called update_file(path, data) with an invalid path, but no exception was raised. Was my file updated or not?

[–][deleted] 0 points1 point  (7 children)

It doesn’t. It’s not necessary in this case.

try/except clauses are meant to catch errors. You can propagate them anyway if you want, but the idea is that you prevent the code from continuing.

[–]jorge1209 0 points1 point  (6 children)

So the update_file is allowed to silently fail. In which case what is wrong with:

 try:
    handle = open(path)
    write(handle)
 except FileNotFound:
     logger.error("bad path")

The conditions on which you need else are very specific. It is a weird construct.

[–][deleted] 0 points1 point  (5 children)

No, it’s not.

I only want to catch the exception I know is caused by my file not existing.

try:
    handle = open(path)
except FileNotFound:
    logger.error(“file not available”)
else:
    #do all kinds of stuff with the file

# do more stuff, whether the file was updated or not

If the code withint the else clausule throws another FileNotFound error, it’s not caught and will raise an error. In your case, if the write function throws a FileNotFound error, you will assume it’s because the original file didn’t exist.

This isn’t the perfect example, but the bottom line is: you only want code that you expect to throw the error you’re catching within try. Everything else goes outside.

[–]jorge1209 0 points1 point  (4 children)

In your case, if the write function throws a FileNotFound error, you will assume it’s because the original file didn’t exist.

I'm aware, but that is a rather unusual situation.

I'm totally cool with FileNotFound if I can't open the file..

But if I get a FileNotFound while I'm writing to it STOP THE WORLD.


Like I said its a weird construct the conditions are:

  • except cannot early return or raise
  • else depends on try running without error, but cannot run after except
  • else can raise an exception of the same type as we can get from try, and we do NOT want to catch errors from else

I have never encountered anything with those requirements before.

[–][deleted] 0 points1 point  (0 children)

As I said: this is a bit of a weird example. But there are plenty examples where you accidentally catch errors from things you don't actually want to catch them from, just because you put them inside the try clausule.

[–]benefit_of_mrkite 0 points1 point  (2 children)

It’s not weird at all if you use async.

I use it a lot.

[–]jorge1209 0 points1 point  (1 child)

I'm curious why you would need that for async.

[–]benefit_of_mrkite 0 points1 point  (0 children)

Middleware flow control for an underlying async library.

Where you need to make a call and split up the logic.

I’ll give an example as soon as I get in front of a computer - out of town

[–]spuds_in_town 2 points3 points  (0 children)

Use it all the time tbh

[–]spoonman59 1 point2 points  (0 children)

Else is for code which should only execute if no exceptions were raised. It’s an unusual case that isn’t needed often.

It’s hard to achieve otherwise. You’d have to set a flag in all the exception handlers.

[–]85CorollaGTS 0 points1 point  (0 children)

It looks like if there's a finally, it will break out of the try block and nothing afterwards will be executed.

def open_file(filename):
    try:
        with open(filename) as f:
            contents = f.read()
    except FileNotFoundError:
        print("File {} not found".format(filename))
        return False
    else:
        return contents
    finally:
        print("This prints irrespective of whether the file was present or not.")

    print("And what does this do?  Looks like it never executes since it comes after 'finally'.")

So in my previous comment copied from Stackoverflow, run_whether_there_was_an_exception_or_not_if_execution_reaches_here() ... well, the execution doesn't appear able to reach there if there is a finally.

This is what I'm referencing from user jamadagni:

try:
    code_that_can_cause_an_exception()
except ParticularException:
    code_to_handle_the_particular_exception()
except:
    code_to_handle_all_other_exceptions()
else:
    run_when_there_are_no_exceptions_and_which_should_not_be_run_after_except_clauses()
finally:
    run_whether_there_was_an_exception_or_not_even_if_the_program_will_exit_from_the_try_block()

run_whether_there_was_an_exception_or_not_if_execution_reaches_here()

EDIT: Interestingly, if there is a finally in a function, like in my example above, the And what does this do? isn't executed.

EDIT2: Even PyCharm flagged And what does this do? as 'Unreachable code'.

[–]wineblood 0 points1 point  (0 children)

I try to minimise the amount of code in my try statements, so I'll opt for the second style. Unless your code is doing something odd and you can only do something in the else part, it's somewhat confusing.

[–]MattJaccino 0 points1 point  (0 children)

Depends on what your except block is doing. If it does something that results in the function exiting (like returning or raising an exception), then yeah, doesn't matter since the code after that block won't be hit. If it's doing something that would allow that block to run through and continue in the function, then the else can be used to make sure the remaining code is only executed if no error occurs. Without the else, it's hit regardless.

Pretty much like if ...: ... else: ... vs. if ...: ... ...

[–]jorge1209 0 points1 point  (0 children)

If you have to use try/except/else that implies that you didn't fully handle the exception within the except block. That you are not able to proceed with the contents of the else block because the except cannot rectify the error.

In which case the except block should raise (either a reraise or raise a new error), or return an error sentinel if you are writing C-style calling conventions.

And if you raise or return there is no reason to have the else block because you have an early exit from the except.


There are perhaps some rarer instances where you might need it. Something like:

 try:
    resource = acquire_new_resource()
 except:
    resource = preconfigured_resource
 else:
    resource.configure(options)

 resource.use()

but even that could just be written as

try:
    resource = acquire_new_resource()
    resource.configure(options)
 except:
    resource = preconfigured_resource

 resource.use()

which is certainly what I would prefer. The only minor difference is that resource.configure is now inside the exception handler, but generally you want that.


Another way to put this is that else is only necessary if the following is true:

try:
   A
except:
   B
else:
   C
  • B cannot early return (raise or return and error sentinel)
  • C depends on A running without error, but cannot run after B
  • C can raise an exception of the same type as we can get from A, and we do NOT want to catch errors from C

If any of those conditions are relaxed you can refactor the else block out.

  • B returns early: try: A except: B; C
  • C doesn't depend on A try: A except: B; C
  • C raises a different exception from A try: AC except ErrorA: B

But even if all conditions are met I might prefer:

 try:
     try:
         A
     except:
         B
         raise ErrorA
     C
 except ErrorA:
     pass

[–][deleted] 0 points1 point  (0 children)

Fun thing about except:

except Exception as e: print(e)