I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 638 posts at DZone. You can read more from them at their website. View Full User Profile

Everything you need to know about Python exceptions

03.08.2012
| 5629 views |
  • submit to reddit
Exceptions are the modern way to substitute error codes to signal errors, and are mainly present in object-oriented languages both static and dynamic. Exceptions are also a first-class mechanism in Python.

Implementation: similar to other languages

Exceptions are objects of particular classes dedicated only to model errors. When raised (or thrown, depending on the jargon), they interrupt the normal flow of the code: they bubble up to the calling method (and the method above that in the stack trace) until they:
  • are handled via a specific construct (caught).
  • Get at the topmost level, causing the program to terminate.
Exceptions, like many language classes, are organized in a hierarchy so that catching can work at different level of precision: you can specify you want to handle a ArithmeticError if you are in your own module, while at the highest level you'll probably manage any Exception instance to avoid termination. Even in catastrophic cases, it's nicer to log an error and displaying a real error message to the user instead of an exception.

Syntax

The try/except construct handles exceptions in Python:
languages = ["c", "python", "php", "java"]
print languages.index("python")
try:
    print languages.index("English")
except ValueError:
    print "English is not a *programming* language"

In many languages except is called catch. Of course multiple except blocks can be specified to handle different exceptions.

raise raises your own exception, which should be an object of a class descending from Exception, usually named with the *Error suffix:

try:
    raise ValueError("English")
except ValueError:
    print "English is not a *programming* language"

raise called without arguments just raises again the last caught exception:

try:
    raise ValueError("English")
except ValueError as e:
    raise

except can also bind a local variable to the exception if you need to inspect it:

try:
    raise ValueError("English")
except ValueError as e:
    print e.__class__           # <type 'exceptions.ValueError'>
    print sys.exc_info()        # the tuple (<type 'exceptions.ValueError'>, ValueError('English',), <traceback object at 0xb779b874>)

You can add an else block to perform some work in the absence of errors:

try:
    print languages.index("c")
except ValueError:
    print "C is not a *programming* language"
else:
    print "C is a programming language"

finally defines a block of code which will always be executed, even if you return early from the try, or do not specify an except block:

try:
    print languages.index("c")
except ValueError:
    print "C is not a *programming* language"
finally:
    print "By the way, there were %s languages" % (len(languages), )

finally is meant to clean up even if the worst case scenario happens.

The traceback module is handy for displaying debug information about the last caught exception:

try:
    print languages.index("English")
except ValueError:
    traceback.print_exc()
    traceback.print_stack()     # only the stack trace

The hierarchy of built-in exceptions

At the Python's reference manual you'll find a full hierarchy of built-in exceptions, useful when catching them or when deciding which class your exception should inherit from.

Here's a condensed version of the hierarchy, omitting many minor exceptions:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      +-- Warning
           +-- DeprecationWarning
           +-- SyntaxWarning

Note that since Python is usually interpreted (or compiled just in time in .pyc modules) there are even errors related to the syntax or issues in importing modules.

When defining your own exception, you should extend at least Exception. Other BaseException derivatives are reserved and should not be caught by any other than the interpreter, like SystemExit.

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)