diff options
Diffstat (limited to 'Doc/tutorial/errors.rst')
-rw-r--r-- | Doc/tutorial/errors.rst | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst new file mode 100644 index 0000000..99af9c7 --- /dev/null +++ b/Doc/tutorial/errors.rst @@ -0,0 +1,418 @@ +.. _tut-errors: + +********************* +Errors and Exceptions +********************* + +Until now error messages haven't been more than mentioned, but if you have tried +out the examples you have probably seen some. There are (at least) two +distinguishable kinds of errors: *syntax errors* and *exceptions*. + + +.. _tut-syntaxerrors: + +Syntax Errors +============= + +Syntax errors, also known as parsing errors, are perhaps the most common kind of +complaint you get while you are still learning Python:: + + >>> while True print 'Hello world' + File "<stdin>", line 1, in ? + while True print 'Hello world' + ^ + SyntaxError: invalid syntax + +The parser repeats the offending line and displays a little 'arrow' pointing at +the earliest point in the line where the error was detected. The error is +caused by (or at least detected at) the token *preceding* the arrow: in the +example, the error is detected at the keyword :keyword:`print`, since a colon +(``':'``) is missing before it. File name and line number are printed so you +know where to look in case the input came from a script. + + +.. _tut-exceptions: + +Exceptions +========== + +Even if a statement or expression is syntactically correct, it may cause an +error when an attempt is made to execute it. Errors detected during execution +are called *exceptions* and are not unconditionally fatal: you will soon learn +how to handle them in Python programs. Most exceptions are not handled by +programs, however, and result in error messages as shown here:: + + >>> 10 * (1/0) + Traceback (most recent call last): + File "<stdin>", line 1, in ? + ZeroDivisionError: integer division or modulo by zero + >>> 4 + spam*3 + Traceback (most recent call last): + File "<stdin>", line 1, in ? + NameError: name 'spam' is not defined + >>> '2' + 2 + Traceback (most recent call last): + File "<stdin>", line 1, in ? + TypeError: cannot concatenate 'str' and 'int' objects + +The last line of the error message indicates what happened. Exceptions come in +different types, and the type is printed as part of the message: the types in +the example are :exc:`ZeroDivisionError`, :exc:`NameError` and :exc:`TypeError`. +The string printed as the exception type is the name of the built-in exception +that occurred. This is true for all built-in exceptions, but need not be true +for user-defined exceptions (although it is a useful convention). Standard +exception names are built-in identifiers (not reserved keywords). + +The rest of the line provides detail based on the type of exception and what +caused it. + +The preceding part of the error message shows the context where the exception +happened, in the form of a stack traceback. In general it contains a stack +traceback listing source lines; however, it will not display lines read from +standard input. + +:ref:`bltin-exceptions` lists the built-in exceptions and their meanings. + + +.. _tut-handling: + +Handling Exceptions +=================== + +It is possible to write programs that handle selected exceptions. Look at the +following example, which asks the user for input until a valid integer has been +entered, but allows the user to interrupt the program (using :kbd:`Control-C` or +whatever the operating system supports); note that a user-generated interruption +is signalled by raising the :exc:`KeyboardInterrupt` exception. :: + + >>> def raw_input(prompt): + ... import sys + ... sys.stdout.write(prompt) + ... sys.stdout.flush() + ... return sys.stdin.readline() + ... + >>> while True: + ... try: + ... x = int(raw_input("Please enter a number: ")) + ... break + ... except ValueError: + ... print "Oops! That was no valid number. Try again..." + ... + +The :keyword:`try` statement works as follows. + +* First, the *try clause* (the statement(s) between the :keyword:`try` and + :keyword:`except` keywords) is executed. + +* If no exception occurs, the *except clause* is skipped and execution of the + :keyword:`try` statement is finished. + +* If an exception occurs during execution of the try clause, the rest of the + clause is skipped. Then if its type matches the exception named after the + :keyword:`except` keyword, the except clause is executed, and then execution + continues after the :keyword:`try` statement. + +* If an exception occurs which does not match the exception named in the except + clause, it is passed on to outer :keyword:`try` statements; if no handler is + found, it is an *unhandled exception* and execution stops with a message as + shown above. + +A :keyword:`try` statement may have more than one except clause, to specify +handlers for different exceptions. At most one handler will be executed. +Handlers only handle exceptions that occur in the corresponding try clause, not +in other handlers of the same :keyword:`try` statement. An except clause may +name multiple exceptions as a parenthesized tuple, for example:: + + ... except (RuntimeError, TypeError, NameError): + ... pass + +The last except clause may omit the exception name(s), to serve as a wildcard. +Use this with extreme caution, since it is easy to mask a real programming error +in this way! It can also be used to print an error message and then re-raise +the exception (allowing a caller to handle the exception as well):: + + import sys + + try: + f = open('myfile.txt') + s = f.readline() + i = int(s.strip()) + except IOError as e: + (errno, strerror) = e + print "I/O error(%s): %s" % (e.errno, e.strerror) + except ValueError: + print "Could not convert data to an integer." + except: + print "Unexpected error:", sys.exc_info()[0] + raise + +The :keyword:`try` ... :keyword:`except` statement has an optional *else +clause*, which, when present, must follow all except clauses. It is useful for +code that must be executed if the try clause does not raise an exception. For +example:: + + for arg in sys.argv[1:]: + try: + f = open(arg, 'r') + except IOError: + print 'cannot open', arg + else: + print arg, 'has', len(f.readlines()), 'lines' + f.close() + +The use of the :keyword:`else` clause is better than adding additional code to +the :keyword:`try` clause because it avoids accidentally catching an exception +that wasn't raised by the code being protected by the :keyword:`try` ... +:keyword:`except` statement. + +When an exception occurs, it may have an associated value, also known as the +exception's *argument*. The presence and type of the argument depend on the +exception type. + +The except clause may specify a variable after the exception name (or tuple). +The variable is bound to an exception instance with the arguments stored in +``instance.args``. For convenience, the exception instance defines +:meth:`__getitem__` and :meth:`__str__` so the arguments can be accessed or +printed directly without having to reference ``.args``. + +But use of ``.args`` is discouraged. Instead, the preferred use is to pass a +single argument to an exception (which can be a tuple if multiple arguments are +needed) and have it bound to the ``message`` attribute. One may also +instantiate an exception first before raising it and add any attributes to it as +desired. :: + + >>> try: + ... raise Exception('spam', 'eggs') + ... except Exception as inst: + ... print type(inst) # the exception instance + ... print inst.args # arguments stored in .args + ... print inst # __str__ allows args to printed directly + ... x, y = inst # __getitem__ allows args to be unpacked directly + ... print 'x =', x + ... print 'y =', y + ... + <type 'Exception'> + ('spam', 'eggs') + ('spam', 'eggs') + x = spam + y = eggs + +If an exception has an argument, it is printed as the last part ('detail') of +the message for unhandled exceptions. + +Exception handlers don't just handle exceptions if they occur immediately in the +try clause, but also if they occur inside functions that are called (even +indirectly) in the try clause. For example:: + + >>> def this_fails(): + ... x = 1/0 + ... + >>> try: + ... this_fails() + ... except ZeroDivisionError as detail: + ... print 'Handling run-time error:', detail + ... + Handling run-time error: integer division or modulo by zero + + +.. _tut-raising: + +Raising Exceptions +================== + +The :keyword:`raise` statement allows the programmer to force a specified +exception to occur. For example:: + + >>> raise NameError, 'HiThere' + Traceback (most recent call last): + File "<stdin>", line 1, in ? + NameError: HiThere + +The first argument to :keyword:`raise` names the exception to be raised. The +optional second argument specifies the exception's argument. Alternatively, the +above could be written as ``raise NameError('HiThere')``. Either form works +fine, but there seems to be a growing stylistic preference for the latter. + +If you need to determine whether an exception was raised but don't intend to +handle it, a simpler form of the :keyword:`raise` statement allows you to +re-raise the exception:: + + >>> try: + ... raise NameError, 'HiThere' + ... except NameError: + ... print 'An exception flew by!' + ... raise + ... + An exception flew by! + Traceback (most recent call last): + File "<stdin>", line 2, in ? + NameError: HiThere + + +.. _tut-userexceptions: + +User-defined Exceptions +======================= + +Programs may name their own exceptions by creating a new exception class. +Exceptions should typically be derived from the :exc:`Exception` class, either +directly or indirectly. For example:: + + >>> class MyError(Exception): + ... def __init__(self, value): + ... self.value = value + ... def __str__(self): + ... return repr(self.value) + ... + >>> try: + ... raise MyError(2*2) + ... except MyError as e: + ... print 'My exception occurred, value:', e.value + ... + My exception occurred, value: 4 + >>> raise MyError, 'oops!' + Traceback (most recent call last): + File "<stdin>", line 1, in ? + __main__.MyError: 'oops!' + +In this example, the default :meth:`__init__` of :class:`Exception` has been +overridden. The new behavior simply creates the *value* attribute. This +replaces the default behavior of creating the *args* attribute. + +Exception classes can be defined which do anything any other class can do, but +are usually kept simple, often only offering a number of attributes that allow +information about the error to be extracted by handlers for the exception. When +creating a module that can raise several distinct errors, a common practice is +to create a base class for exceptions defined by that module, and subclass that +to create specific exception classes for different error conditions:: + + class Error(Exception): + """Base class for exceptions in this module.""" + pass + + class InputError(Error): + """Exception raised for errors in the input. + + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + + def __init__(self, expression, message): + self.expression = expression + self.message = message + + class TransitionError(Error): + """Raised when an operation attempts a state transition that's not + allowed. + + Attributes: + previous -- state at beginning of transition + next -- attempted new state + message -- explanation of why the specific transition is not allowed + """ + + def __init__(self, previous, next, message): + self.previous = previous + self.next = next + self.message = message + +Most exceptions are defined with names that end in "Error," similar to the +naming of the standard exceptions. + +Many standard modules define their own exceptions to report errors that may +occur in functions they define. More information on classes is presented in +chapter :ref:`tut-classes`. + + +.. _tut-cleanup: + +Defining Clean-up Actions +========================= + +The :keyword:`try` statement has another optional clause which is intended to +define clean-up actions that must be executed under all circumstances. For +example:: + + >>> try: + ... raise KeyboardInterrupt + ... finally: + ... print 'Goodbye, world!' + ... + Goodbye, world! + Traceback (most recent call last): + File "<stdin>", line 2, in ? + KeyboardInterrupt + +A *finally clause* is always executed before leaving the :keyword:`try` +statement, whether an exception has occurred or not. When an exception has +occurred in the :keyword:`try` clause and has not been handled by an +:keyword:`except` clause (or it has occurred in a :keyword:`except` or +:keyword:`else` clause), it is re-raised after the :keyword:`finally` clause has +been executed. The :keyword:`finally` clause is also executed "on the way out" +when any other clause of the :keyword:`try` statement is left via a +:keyword:`break`, :keyword:`continue` or :keyword:`return` statement. A more +complicated example (having :keyword:`except` and :keyword:`finally` clauses in +the same :keyword:`try` statement works as of Python 2.5):: + + >>> def divide(x, y): + ... try: + ... result = x / y + ... except ZeroDivisionError: + ... print "division by zero!" + ... else: + ... print "result is", result + ... finally: + ... print "executing finally clause" + ... + >>> divide(2, 1) + result is 2 + executing finally clause + >>> divide(2, 0) + division by zero! + executing finally clause + >>> divide("2", "1") + executing finally clause + Traceback (most recent call last): + File "<stdin>", line 1, in ? + File "<stdin>", line 3, in divide + TypeError: unsupported operand type(s) for /: 'str' and 'str' + +As you can see, the :keyword:`finally` clause is executed in any event. The +:exc:`TypeError` raised by dividing two strings is not handled by the +:keyword:`except` clause and therefore re-raised after the :keyword:`finally` +clauses has been executed. + +In real world applications, the :keyword:`finally` clause is useful for +releasing external resources (such as files or network connections), regardless +of whether the use of the resource was successful. + + +.. _tut-cleanup-with: + +Predefined Clean-up Actions +=========================== + +Some objects define standard clean-up actions to be undertaken when the object +is no longer needed, regardless of whether or not the operation using the object +succeeded or failed. Look at the following example, which tries to open a file +and print its contents to the screen. :: + + for line in open("myfile.txt"): + print line + +The problem with this code is that it leaves the file open for an indeterminate +amount of time after the code has finished executing. This is not an issue in +simple scripts, but can be a problem for larger applications. The +:keyword:`with` statement allows objects like files to be used in a way that +ensures they are always cleaned up promptly and correctly. :: + + with open("myfile.txt") as f: + for line in f: + print line + +After the statement is executed, the file *f* is always closed, even if a +problem was encountered while processing the lines. Other objects which provide +predefined clean-up actions will indicate this in their documentation. + + |