tags:

views:

2381

answers:

9
+6  Q: 

Python try-else

I am just now learning Python, and I came across an interesting construct. In Python, the try block has an optional else block. Other than providing a new scope after the try exits normally, what does the else block do for you? Or is that just it?

+18  A: 

The statements in the else block are executed if execution falls off the bottom of the try - if there was no exception. Honestly, I've never found a need.

However, Handling Exceptions notes:

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.

So, if you have a method that could, for example, throw an IOError, and you want to catch exceptions it raises, but there's something else you want to do if the first operation succeeds, and you don't want to catch an IOError from that operation, you might write something like this:

    try:
        operation_that_can_throw_ioerror()
    except IOError:
        handle_the_exception_somehow()
    else:
         # we don't want to catch the IOError if it's raised
        another_operation_that_can_throw_ioerror()
    finally:
        something_we_always_need_to_do()

If you just put another_operation_that_can_throw_ioerror() after operation_that_can_throw_ioerror, the except would catch the second call's errors. And if you put it after the whole try block, it'll always be run, and not until after the finally. The else lets you make sure

  1. the second operation's only run if there's no exception,
  2. it's run before the finally block, and
  3. any IOErrors it raises aren't caught here
Blair Conrad
I think this answer gave a very clear description of when it's useful. +1
Carl Meyer
Thanks, @Carl Meyer. Just in case others are confused later, the original answer had less content, and I'd agree that it didn't fully meet @George IV's needs.
Blair Conrad
+2  A: 

Never used it myself. Looking at Python reference it seems that else is executed after try when there's no exception. The optional else clause is executed if and when control flows off the end of the try clause. [2] Exceptions in the else clause are not handled by the preceding except clauses.

Dive into python has and example where, if I understand correctly, in try block they try to import a module, when that fails you get exception and bind default but when it works you have an option to go into else block and bind what is required (see link for the example and explanation).

If you tried to do work in catch block it might throw another exception - I guess that's where the else block comes handy.

stefanB
"Exceptions in the else clause are not handled by the preceding except clauses." That is the useful part. Thank you.
geowa4
A: 

Even though you can't think of a use of it right now, you can bet there has to be a use for it. Here is an unimaginative sample out of my head:

a = [1,2,3]
try:
    something = a[2]
except:
    print "out of bounds"
else:
    print something


try:
    something = a[2]
except:
    print "out of bounds"

if "something" in locals():
    print something

Here you have the variable "something" defined if no error is thrown. You can remove this outside the try block, but then it requires some messy detection if a variable is defined.

Unknown
What's wrong with `something = a[2]; print something` inside the try: block?
S.Lott
@ S.Lott nothing, but what if someone is sending you a list, and you don't want to display the data if its not long enough because it is probably corrupted?
Unknown
S. Lott: 'print something' could raise a different exception that you don't want to intercept.
Darius Bacon
I don't see the difference. If I get an out of bounds exception, it prints "out of bounds". Got that. If I get some other exception, it's uncaught by this block of code. If I get no exception, the behavior is to print the value of something, which is a[2]. I don't see what the else does in this example.
S.Lott
The value of 'something', when printed, might raise the error in its __str__() method. While that value is actually just 2 in this example, you might just as well point out that there is no out-of-bounds exception here either.
Darius Bacon
A: 

The else: block is confusing and (nearly) useless. It's also part of the for and while statements.

Actually, even on an if-statement, the else: can be abused in truly terrible ways creating bugs that are very hard to find.

Consider this.

   if a < 10:
       # condition stated explicitly
   elif a > 10 and b < 10:
       # condition confusing but at least explicit
   else:
       # Exactly what is true here?
       # Can be hard to reason out what condition is true

Think twice about else:. It is generally a problem. Avoid it except in an if-statement and even then consider documenting the else- condition to make it explicit.

S.Lott
I would disagree with this one.In "if-elif" block, "else" is used as "default" would be used in "case" block of C language.It is always recommended to handle "default" case even if you think you've covered all cases in various conditions.
Josip
@Josip: used as a "default" can be confusing. The issue is to clearly define the condition that is this "default". A poorly-defined default condition can be the root cause of buggy behavior. Else can be a cause of confusion. It should be thought through very carefully in all cases, not just try, for and while, but if as well.
S.Lott
+1 Agree with the idea.
ilya n.
+3  A: 

I find it really useful when you've got cleanup to do that has to be done even if there's an exception:

try:
    data = something_that_can_go_wrong()
except Exception, e: # yes, I know that's a bad way to do it...
    handle_exception(e)
else:
    do_stuff(data)
finally:
    clean_up()
RoadieRich
You find "finally" useful, not "else", for cleanup code.
ΤΖΩΤΖΙΟΥ
Yeah, but else is useful if there's operations to perform BEFORE the cleanup, as my pseudocode example shows.
RoadieRich
+4  A: 

One use: test some code that should raise an exception.

try:
    this_should_raise_TypeError()
except TypeError:
    pass
except:
    assert False, "Raised the wrong exception type"
else:
    assert False, "Didn't raise any exception"

(This code should be abstracted into a more generic test in practice.)

Darius Bacon
A: 

That's it. The 'else' block of a try-except clause exists for code that runs when (and only when) the tried operation succeeds. It can be used, and it can be abused.

try:
    fp= open("configuration_file", "rb")
except EnvironmentError:
    confdata= '' # it's ok if the file can't be opened
else:
    confdata= fp.read()
    fp.close()

# your code continues here
# working with (possibly empty) confdata

Personally, I like it and use it when appropriate. It semantically groups statements.

ΤΖΩΤΖΙΟΥ
A: 

An else block can often exist to complement functionality that occurs in every except block.

try:
    test_consistency(valuable_data)
except Except1:
    inconsistency_type = 1
except Except2:
    inconsistency_type = 2
except:
    # Something else is wrong
    raise
else:
    inconsistency_type = 0

"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""

In this case, inconsistency_type is set in each except block, so that behaviour is complemented in the no-error case in else.

Of course, I'm describing this as a pattern that may turn up in your own code someday. In this specific case, you just set inconsistency_type to 0 before the try block anyway.

Wesley
+1  A: 

There's a nice example of try-else in PEP 380. Basically, it comes down to doing different exception handling in different parts of the algorithm.

It's something like this:

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

This allows you to write the exception handling code nearer to where the exception occurs.

itsadok