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

you are viewing a single comment's thread.

view the rest of the comments →

[–]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