Everything you need to know about Python exceptions
Implementation: similar to other languagesExceptions 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.
SyntaxThe 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.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)