8.Errors and Exceptions¶
Until now error messages haven’t been more than mentioned, but if you have triedout the examples you have probably seen some. There are (at least) twodistinguishable kinds of errors:syntax errors andexceptions.
8.1.Syntax Errors¶
Syntax errors, also known as parsing errors, are perhaps the most common kind ofcomplaint you get while you are still learning Python:
>>>whileTrueprint('Hello world') File"<stdin>", line1whileTrueprint('Hello world')^SyntaxError:invalid syntax
The parser repeats the offending line and displays a little ‘arrow’ pointing atthe earliest point in the line where the error was detected. The error iscaused by (or at least detected at) the tokenpreceding the arrow: in theexample, the error is detected at the functionprint()
, since a colon(':'
) is missing before it. File name and line number are printed so youknow where to look in case the input came from a script.
8.2.Exceptions¶
Even if a statement or expression is syntactically correct, it may cause anerror when an attempt is made to execute it. Errors detected during executionare calledexceptions and are not unconditionally fatal: you will soon learnhow to handle them in Python programs. Most exceptions are not handled byprograms, however, and result in error messages as shown here:
>>>10*(1/0)Traceback (most recent call last): File"<stdin>", line1, in<module>ZeroDivisionError:division by zero>>>4+spam*3Traceback (most recent call last): File"<stdin>", line1, in<module>NameError:name 'spam' is not defined>>>'2'+2Traceback (most recent call last): File"<stdin>", line1, in<module>TypeError:can only concatenate str (not "int") to str
The last line of the error message indicates what happened. Exceptions come indifferent types, and the type is printed as part of the message: the types inthe example areZeroDivisionError
,NameError
andTypeError
.The string printed as the exception type is the name of the built-in exceptionthat occurred. This is true for all built-in exceptions, but need not be truefor user-defined exceptions (although it is a useful convention). Standardexception names are built-in identifiers (not reserved keywords).
The rest of the line provides detail based on the type of exception and whatcaused it.
The preceding part of the error message shows the context where the exceptionoccurred, in the form of a stack traceback. In general it contains a stacktraceback listing source lines; however, it will not display lines read fromstandard input.
Built-in Exceptions lists the built-in exceptions and their meanings.
8.3.Handling Exceptions¶
It is possible to write programs that handle selected exceptions. Look at thefollowing example, which asks the user for input until a valid integer has beenentered, but allows the user to interrupt the program (usingControl-C orwhatever the operating system supports); note that a user-generated interruptionis signalled by raising theKeyboardInterrupt
exception.
>>>whileTrue:...try:...x=int(input("Please enter a number: "))...break...exceptValueError:...print("Oops! That was no valid number. Try again...")...
Thetry
statement works as follows.
First, thetry clause (the statement(s) between the
try
andexcept
keywords) is executed.If no exception occurs, theexcept clause is skipped and execution of the
try
statement is finished.If an exception occurs during execution of the try clause, the rest of theclause is skipped. Then if its type matches the exception named after the
except
keyword, the except clause is executed, and then executioncontinues after thetry
statement.If an exception occurs which does not match the exception named in the exceptclause, it is passed on to outer
try
statements; if no handler isfound, it is anunhandled exception and execution stops with a message asshown above.
Atry
statement may have more than one except clause, to specifyhandlers for different exceptions. At most one handler will be executed.Handlers only handle exceptions that occur in the corresponding try clause, notin other handlers of the sametry
statement. An except clause mayname multiple exceptions as a parenthesized tuple, for example:
...except(RuntimeError,TypeError,NameError):...pass
A class in anexcept
clause is compatible with an exception if it isthe same class or a base class thereof (but not the other way around — anexcept clause listing a derived class is not compatible with a base class). Forexample, the following code will print B, C, D in that order:
classB(Exception):passclassC(B):passclassD(C):passforclsin[B,C,D]:try:raisecls()exceptD:print("D")exceptC:print("C")exceptB:print("B")
Note that if the except clauses were reversed (withexceptB
first), itwould have printed B, B, B — the first matching except clause is triggered.
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 errorin this way! It can also be used to print an error message and then re-raisethe exception (allowing a caller to handle the exception as well):
importsystry:f=open('myfile.txt')s=f.readline()i=int(s.strip())exceptOSErroraserr:print("OS error:{0}".format(err))exceptValueError:print("Could not convert data to an integer.")except:print("Unexpected error:",sys.exc_info()[0])raise
Thetry
…except
statement has an optionalelseclause, which, when present, must follow all except clauses. It is useful forcode that must be executed if the try clause does not raise an exception. Forexample:
forarginsys.argv[1:]:try:f=open(arg,'r')exceptOSError:print('cannot open',arg)else:print(arg,'has',len(f.readlines()),'lines')f.close()
The use of theelse
clause is better than adding additional code tothetry
clause because it avoids accidentally catching an exceptionthat wasn’t raised by the code being protected by thetry
…except
statement.
When an exception occurs, it may have an associated value, also known as theexception’sargument. The presence and type of the argument depend on theexception type.
The except clause may specify a variable after the exception name. Thevariable is bound to an exception instance with the arguments stored ininstance.args
. For convenience, the exception instance defines__str__()
so the arguments can be printed directly without having toreference.args
. One may also instantiate an exception first beforeraising it and add any attributes to it as desired.
>>>try:...raiseException('spam','eggs')...exceptExceptionasinst:...print(type(inst))# the exception instance...print(inst.args)# arguments stored in .args...print(inst)# __str__ allows args to be printed directly,...# but may be overridden in exception subclasses...x,y=inst.args# unpack args...print('x =',x)...print('y =',y)...<class 'Exception'>('spam', 'eggs')('spam', 'eggs')x = spamy = eggs
If an exception has arguments, they are printed as the last part (‘detail’) ofthe message for unhandled exceptions.
Exception handlers don’t just handle exceptions if they occur immediately in thetry clause, but also if they occur inside functions that are called (evenindirectly) in the try clause. For example:
>>>defthis_fails():...x=1/0...>>>try:...this_fails()...exceptZeroDivisionErroraserr:...print('Handling run-time error:',err)...Handling run-time error: division by zero
8.4.Raising Exceptions¶
Theraise
statement allows the programmer to force a specifiedexception to occur. For example:
>>>raiseNameError('HiThere')Traceback (most recent call last): File"<stdin>", line1, in<module>NameError:HiThere
The sole argument toraise
indicates the exception to be raised.This must be either an exception instance or an exception class (a class thatderives fromException
). If an exception class is passed, it willbe implicitly instantiated by calling its constructor with no arguments:
raiseValueError# shorthand for 'raise ValueError()'
If you need to determine whether an exception was raised but don’t intend tohandle it, a simpler form of theraise
statement allows you tore-raise the exception:
>>>try:...raiseNameError('HiThere')...exceptNameError:...print('An exception flew by!')...raise...An exception flew by!Traceback (most recent call last): File"<stdin>", line2, in<module>NameError:HiThere
8.5.Exception Chaining¶
Theraise
statement allows an optionalfrom
which enableschaining exceptions. For example:
# exc must be exception instance or None.raiseRuntimeErrorfromexc
This can be useful when you are transforming exceptions. For example:
>>>deffunc():...raiseIOError...>>>try:...func()...exceptIOErrorasexc:...raiseRuntimeError('Failed to open database')fromexc...Traceback (most recent call last): File"<stdin>", line2, in<module> File"<stdin>", line2, infuncOSErrorThe above exception was the direct cause of the following exception:Traceback (most recent call last): File"<stdin>", line4, in<module>RuntimeError:Failed to open database
Exception chaining happens automatically when an exception is raised inside anexcept
orfinally
section. Exception chaining can bedisabled by usingfromNone
idiom:
>>>try:...open('database.sqlite')...exceptOSError:...raiseRuntimeErrorfromNone...Traceback (most recent call last): File"<stdin>", line4, in<module>RuntimeError
For more information about chaining mechanics, seeBuilt-in Exceptions.
8.6.User-defined Exceptions¶
Programs may name their own exceptions by creating a new exception class (seeClasses for more about Python classes). Exceptions should typicallybe derived from theException
class, either directly or indirectly.
Exception classes can be defined which do anything any other class can do, butare usually kept simple, often only offering a number of attributes that allowinformation about the error to be extracted by handlers for the exception.
Most exceptions are defined with names that end in “Error”, similar to thenaming of the standard exceptions.
Many standard modules define their own exceptions to report errors that mayoccur in functions they define. More information on classes is presented inchapterClasses.
8.7.Defining Clean-up Actions¶
Thetry
statement has another optional clause which is intended todefine clean-up actions that must be executed under all circumstances. Forexample:
>>>try:...raiseKeyboardInterrupt...finally:...print('Goodbye, world!')...Goodbye, world!Traceback (most recent call last): File"<stdin>", line2, in<module>KeyboardInterrupt
If afinally
clause is present, thefinally
clause will execute as the last task before thetry
statement completes. Thefinally
clause runs whether ornot thetry
statement produces an exception. The followingpoints discuss more complex cases when an exception occurs:
If an exception occurs during execution of the
try
clause, the exception may be handled by anexcept
clause. If the exception is not handled by anexcept
clause, the exception is re-raised after thefinally
clause has been executed.An exception could occur during execution of an
except
orelse
clause. Again, the exception is re-raised afterthefinally
clause has been executed.If the
finally
clause executes abreak
,continue
orreturn
statement, exceptions are notre-raised.If the
try
statement reaches abreak
,continue
orreturn
statement, thefinally
clause will execute just prior to thebreak
,continue
orreturn
statement’s execution.If a
finally
clause includes areturn
statement, the returned value will be the one from thefinally
clause’sreturn
statement, not thevalue from thetry
clause’sreturn
statement.
For example:
>>>defbool_return():...try:...returnTrue...finally:...returnFalse...>>>bool_return()False
A more complicated example:
>>>defdivide(x,y):...try:...result=x/y...exceptZeroDivisionError:...print("division by zero!")...else:...print("result is",result)...finally:...print("executing finally clause")...>>>divide(2,1)result is 2.0executing finally clause>>>divide(2,0)division by zero!executing finally clause>>>divide("2","1")executing finally clauseTraceback (most recent call last): File"<stdin>", line1, in<module> File"<stdin>", line3, individeTypeError:unsupported operand type(s) for /: 'str' and 'str'
As you can see, thefinally
clause is executed in any event. TheTypeError
raised by dividing two strings is not handled by theexcept
clause and therefore re-raised after thefinally
clause has been executed.
In real world applications, thefinally
clause is useful forreleasing external resources (such as files or network connections), regardlessof whether the use of the resource was successful.
8.8.Predefined Clean-up Actions¶
Some objects define standard clean-up actions to be undertaken when the objectis no longer needed, regardless of whether or not the operation using the objectsucceeded or failed. Look at the following example, which tries to open a fileand print its contents to the screen.
forlineinopen("myfile.txt"):print(line,end="")
The problem with this code is that it leaves the file open for an indeterminateamount of time after this part of the code has finished executing.This is not an issue in simple scripts, but can be a problem for largerapplications. Thewith
statement allows objects like files to beused in a way that ensures they are always cleaned up promptly and correctly.
withopen("myfile.txt")asf:forlineinf:print(line,end="")
After the statement is executed, the filef is always closed, even if aproblem was encountered while processing the lines. Objects which, like files,provide predefined clean-up actions will indicate this in their documentation.