views:

227

answers:

7

When I write code in Python with exception handling I can write code like:

try:
    some_code_that_can_cause_an_exception()
except:
    some_code_to_handle_exceptions()
else:
    code_that_needs_to_run_when_there_are_no_exceptions()

How does this differ from:

try:
    some_code_that_can_cause_an_exception()
except:
    some_code_to_handle_exceptions()

code_that_needs_to_run_when_there_are_no_exceptions()

In both cases code_that_needs_to_run_when_there_are_no_exceptions() will execute when there are no exceptions. What's the difference?

+5  A: 

Actually, in the second snippet, the last line executes always.

You probably meant

try:
    some_code_that_can_cause_an_exception()
    code_that_needs_to_run_when_there_are_no_exceptions()
except:
    some_code_to_handle_exceptions()

I believe you can use the else version if it makes the code more readable. You use the else variant if you don't want to catch exceptions from code_that_needs_to_run_when_there_are_no_exceptions.

avakar
Yes, the second snippet always executes, but there is more than a readability/stylistic difference between the first snippet and your sample. In the first snippet, code_that_needs_to_run_where_there_are_no_exceptions() can never cause some_code_to_handle_exceptions() to run, whereas in your snippet it can.
David Berger
David, you're right. As you can see, I realized it about 30 seconds before you posted your comment :)
avakar
+7  A: 

In the second example, code_that_needs_to_run_when_there_are_no_exceptions() will be ran when you do have an exception and then you handle it, continuing after the except.

so ...

In both cases code_that_needs_to_run_when_there_are_no_exceptions() will execute when there are no exceptions, but in the latter will execute when there are and are not exceptions.

Try this on your CLI

#!/usr/bin/python

def throws_ex( raise_it=True ):
        if raise_it:
                raise Exception("Handle me")

def do_more():
        print "doing more\n"

if __name__ == "__main__":
        print "Example 1\n"
        try:
                throws_ex()
        except Exception, e:
                # Handle it
                print "Handling Exception\n"
        else:
                print "No Exceptions\n"
                do_more()

        print "example 2\n"
        try:
                throws_ex()
        except Exception, e:
                print "Handling Exception\n"
        do_more()

        print "example 3\n"
        try:
                throws_ex(False)
        except Exception, e:
                print "Handling Exception\n"
        else:
                do_more()

        print "example 4\n"
        try:
                throws_ex(False)
        except Exception, e:
                print "Handling Exception\n"
        do_more()

It will output

Example 1

Handling Exception

example 2

Handling Exception

doing more

example 3

doing more

example 4

doing more

You get the idea, play around with exceptions, bubbling and other things! Crack out the command-line and VIM!

Aiden Bell
+1  A: 

Hi,

According to the docs...

"The optional else clause is executed if and when control flows off the end of the try clause.7.2 Exceptions in the else clause are not handled by the preceding except clauses."

So look at this basic example as your answer

try:
  print("Try with Exception")
  print(sys.path)
except NameError:
  print "Exception"
else:
  print "Else"

print("Out of try/except block")

try:
  print("Try without Exception")
except NameError:
  print "Exception"
else:
  print "Else is now executed"

print("Out of try/except finally")

See how the else got executed when the exception didn't occur.

rh0dium
+4  A: 

Example 1:

try:
    a()
    b()
except:
    c()

Here, b() will only be run if a() didn't throw, but the except block will also catch any exceptions that may be thrown by b(), which you might not want. A general rule is: only catch exceptions that you know might happen (and have a way of handling). Therefore, if you don't know whether b() will throw, or if you can't do anything useful by catching an exception thrown by b(), then don't put b() in the try: block.

Example 2:

try:
    a()
except:
    c()
else:
    b()

Here, b() will only be run if a() didn't throw, but any exceptions that b() throws will not be caught here and will continue to propagate up the stack. This is very often what you want.

Example 3:

try:
    a()
except:
    c()

b()

Here, b() is always run, even if a() didn't throw anything. This is also quite commonly useful, of course.

John Bartholomew
+3  A: 

You had the original code almost right. Here's the full treatment:

try:
    some_code_that_can_cause_an_exception()
except:
    some_code_to_handle_exceptions()
else:
    code_that_needs_to_run_when_there_are_no_exceptions()

code_that_runs_whether_there_was_an_exception_or_not()
Ned Batchelder
shouldn't `code_that_runs_whether_there_was_an_exception_or_not()` be in a finally block?
Mk12
A: 

I haven't been using Python for all that long, but I try to handle specific exceptions in a try block, and use else to handle the "other" exceptions I might not have expected, similar to a default block in C/C++ switch blocks. Is that an appropriate use for else as well?

ChrisC
Ignore my above post-doesn't work that way at all. Back to the books for me!
ChrisC
+1  A: 

I use try:..except:..else: a lot!

This is the pattern: try..except should span just one line of code where I anticipate an exception. Then except does the fallback/default handling, and else: does the thing I really wanted to do (no exceptions => go on to make what I wanted).

A simple example:

   # Exhibit 1
   data_paths = []
   try:
       from . import version_subst
   except ImportError:
       first_datadir = "./data"
   else:
       first_datadir = os.path.join(version_subst.DATADIR, PACKAGE_NAME)


# Exhibit 2
for attr in attrs:
    try:
        obj = getattr(plugin, attr)
    except AttributeError, e:
        if warn:
            pretty.print_info(__name__, "Plugin %s: %s" % (plugin_name, e))
        yield None
    else:
        yield obj
kaizer.se