8. Errors and Exceptions (2024)

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 and exceptions.

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:

>>> while True print('Hello world') File "<stdin>", line 1 while True print('Hello world') ^^^^^SyntaxError: invalid syntax

The parser repeats the offending line and displays little ‘arrow’s pointingat the token in the line where the error was detected. The error may becaused by the absence of a token before the indicated token. In theexample, the error is detected at the function print(), 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 called exceptions 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>", line 1, in <module>ZeroDivisionError: division by zero>>> 4 + spam*3Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'spam' is not defined>>> '2' + 2Traceback (most recent call last): File "<stdin>", line 1, 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 are ZeroDivisionError, NameError and TypeError.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 (using Control-C orwhatever the operating system supports); note that a user-generated interruptionis signalled by raising the KeyboardInterrupt exception.

>>> while True:...  try:...  x = int(input("Please enter a number: "))...  break...  except ValueError:...  print("Oops! That was no valid number. Try again...")...

The try statement works as follows.

  • First, the try clause (the statement(s) between the try andexcept keywords) is executed.

  • If no exception occurs, the except clause is skipped and execution of thetry 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 theexcept keyword, the except clause is executed, and then executioncontinues after the try/except block.

  • 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 an unhandled exception and execution stops with an error message.

A try 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,not in other handlers of the same try statement. An except clausemay name multiple exceptions as a parenthesized tuple, for example:

... except (RuntimeError, TypeError, NameError):... pass

A class in an except clause matches exceptions which are instances of theclass itself or one of its derived classes (but not the other way around — anexcept clause listing a derived class does not match instances of its base classes).For example, the following code will print B, C, D in that order:

class B(Exception): passclass C(B): passclass D(C): passfor cls in [B, C, D]: try: raise cls() except D: print("D") except C: print("C") except B: print("B")

Note that if the except clauses were reversed (with except B first), itwould have printed B, B, B — the first matching except clause is triggered.

When an exception occurs, it may have associated values, also known as theexception’s arguments. The presence and types of the arguments depend on theexception type.

The except clause may specify a variable after the exception name. Thevariable is bound to the exception instance which typically has an argsattribute that stores the arguments. For convenience, builtin exceptiontypes define __str__() to print all the arguments without explicitlyaccessing .args.

>>> try:...  raise Exception('spam', 'eggs')... except Exception as inst:...  print(type(inst)) # the exception type...  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

The exception’s __str__() output is printed as the last part (‘detail’)of the message for unhandled exceptions.

BaseException is the common base class of all exceptions. One of itssubclasses, Exception, is the base class of all the non-fatal exceptions.Exceptions which are not subclasses of Exception are not typicallyhandled, because they are used to indicate that the program should terminate.They include SystemExit which is raised by sys.exit() andKeyboardInterrupt which is raised when a user wishes to interruptthe program.

Exception can be used as a wildcard that catches (almost) everything.However, it is good practice to be as specific as possible with the typesof exceptions that we intend to handle, and to allow any unexpectedexceptions to propagate on.

The most common pattern for handling Exception is to print or logthe exception and then re-raise it (allowing a caller to handle theexception as well):

import systry: f = open('myfile.txt') s = f.readline() i = int(s.strip())except OSError as err: print("OS error:", err)except ValueError: print("Could not convert data to an integer.")except Exception as err: print(f"Unexpected {err=}, {type(err)=}") raise

The tryexcept statement has an optional elseclause, which, when present, must follow all except clauses. It is usefulfor 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 OSError: print('cannot open', arg) else: print(arg, 'has', len(f.readlines()), 'lines') f.close()

The use of the else clause is better than adding additional code tothe try clause because it avoids accidentally catching an exceptionthat wasn’t raised by the code being protected by the tryexcept statement.

Exception handlers do not handle only exceptions that occur immediately in thetry clause, but also those that occur inside functions that are called (evenindirectly) in the try clause. For example:

>>> def this_fails():...  x = 1/0...>>> try:...  this_fails()... except ZeroDivisionError as err:...  print('Handling run-time error:', err)...Handling run-time error: division by zero

8.4. Raising Exceptions

The raise statement allows the programmer to force a specifiedexception to occur. For example:

>>> raise NameError('HiThere')Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: HiThere

The sole argument to raise indicates the exception to be raised.This must be either an exception instance or an exception class (a class thatderives from BaseException, such as Exception or one of itssubclasses). If an exception class is passed, it will be implicitlyinstantiated by calling its constructor with no arguments:

raise ValueError # shorthand for 'raise ValueError()'

If you need to determine whether an exception was raised but don’t intend tohandle it, a simpler form of the raise statement allows you tore-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 <module>NameError: HiThere

8.5. Exception Chaining

If an unhandled exception occurs inside an except section, it willhave the exception being handled attached to it and included in the errormessage:

>>> try:...  open("database.sqlite")... except OSError:...  raise RuntimeError("unable to handle error")...Traceback (most recent call last): File "<stdin>", line 2, in <module>FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite'During handling of the above exception, another exception occurred:Traceback (most recent call last): File "<stdin>", line 4, in <module>RuntimeError: unable to handle error

To indicate that an exception is a direct consequence of another, theraise statement allows an optional from clause:

# exc must be exception instance or None.raise RuntimeError from exc

This can be useful when you are transforming exceptions. For example:

>>> def func():...  raise ConnectionError...>>> try:...  func()... except ConnectionError as exc:...  raise RuntimeError('Failed to open database') from exc...Traceback (most recent call last): File "<stdin>", line 2, in <module> File "<stdin>", line 2, in funcConnectionErrorThe above exception was the direct cause of the following exception:Traceback (most recent call last): File "<stdin>", line 4, in <module>RuntimeError: Failed to open database

It also allows disabling automatic exception chaining using the from Noneidiom:

>>> try:...  open('database.sqlite')... except OSError:...  raise RuntimeError from None...Traceback (most recent call last): File "<stdin>", line 4, in <module>RuntimeError

For more information about chaining mechanics, see Built-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 the Exception 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.

8.7. Defining Clean-up Actions

The try statement has another optional clause which is intended todefine clean-up actions that must be executed under all circ*mstances. Forexample:

>>> try:...  raise KeyboardInterrupt... finally:...  print('Goodbye, world!')...Goodbye, world!Traceback (most recent call last): File "<stdin>", line 2, in <module>KeyboardInterrupt

If a finally clause is present, the finallyclause will execute as the last task before the trystatement completes. The finally clause runs whether ornot the try statement produces an exception. The followingpoints discuss more complex cases when an exception occurs:

  • If an exception occurs during execution of the tryclause, the exception may be handled by an exceptclause. If the exception is not handled by an exceptclause, the exception is re-raised after the finallyclause has been executed.

  • An exception could occur during execution of an exceptor else clause. Again, the exception is re-raised afterthe finally clause has been executed.

  • If the finally clause executes a break,continue or return statement, exceptions are notre-raised.

  • If the try statement reaches a break,continue or return statement, thefinally clause will execute just prior to thebreak, continue or returnstatement’s execution.

  • If a finally clause includes a returnstatement, the returned value will be the one from thefinally clause’s return statement, not thevalue from the try clause’s returnstatement.

For example:

>>> def bool_return():...  try:...  return True...  finally:...  return False...>>> bool_return()False

A more complicated example:

>>> 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.0executing finally clause>>> divide(2, 0)division by zero!executing finally clause>>> divide("2", "1")executing finally clauseTraceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in divideTypeError: unsupported operand type(s) for /: 'str' and 'str'

As you can see, the finally clause is executed in any event. TheTypeError raised by dividing two strings is not handled by theexcept clause and therefore re-raised after the finallyclause has been executed.

In real world applications, the finally 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.

for line in open("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. The with statement allows objects like files to beused 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, end="")

After the statement is executed, the file f 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.

8.9. Raising and Handling Multiple Unrelated Exceptions

There are situations where it is necessary to report several exceptions thathave occurred. This is often the case in concurrency frameworks, when severaltasks may have failed in parallel, but there are also other use cases whereit is desirable to continue execution and collect multiple errors rather thanraise the first exception.

The builtin ExceptionGroup wraps a list of exception instances sothat they can be raised together. It is an exception itself, so it can becaught like any other exception.

>>> def f():...  excs = [OSError('error 1'), SystemError('error 2')]...  raise ExceptionGroup('there were problems', excs)...>>> f() + Exception Group Traceback (most recent call last): | File "<stdin>", line 1, in <module> | File "<stdin>", line 3, in f | ExceptionGroup: there were problems +-+---------------- 1 ---------------- | OSError: error 1 +---------------- 2 ---------------- | SystemError: error 2 +------------------------------------>>> try:...  f()... except Exception as e:...  print(f'caught {type(e)}: e')...caught <class 'ExceptionGroup'>: e>>>

By using except* instead of except, we can selectivelyhandle only the exceptions in the group that match a certaintype. In the following example, which shows a nested exceptiongroup, each except* clause extracts from the group exceptionsof a certain type while letting all other exceptions propagate toother clauses and eventually to be reraised.

>>> def f():...  raise ExceptionGroup(...  "group1",...  [...  OSError(1),...  SystemError(2),...  ExceptionGroup(...  "group2",...  [...  OSError(3),...  RecursionError(4)...  ]...  )...  ]...  )...>>> try:...  f()... except* OSError as e:...  print("There were OSErrors")... except* SystemError as e:...  print("There were SystemErrors")...There were OSErrorsThere were SystemErrors + Exception Group Traceback (most recent call last): | File "<stdin>", line 2, in <module> | File "<stdin>", line 2, in f | ExceptionGroup: group1 +-+---------------- 1 ---------------- | ExceptionGroup: group2 +-+---------------- 1 ---------------- | RecursionError: 4 +------------------------------------>>>

Note that the exceptions nested in an exception group must be instances,not types. This is because in practice the exceptions would typicallybe ones that have already been raised and caught by the program, alongthe following pattern:

>>> excs = []... for test in tests:...  try:...  test.run()...  except Exception as e:...  excs.append(e)...>>> if excs:...  raise ExceptionGroup("Test Failures", excs)...

8.10. Enriching Exceptions with Notes

When an exception is created in order to be raised, it is usually initializedwith information that describes the error that has occurred. There are caseswhere it is useful to add information after the exception was caught. For thispurpose, exceptions have a method add_note(note) that accepts a string andadds it to the exception’s notes list. The standard traceback renderingincludes all notes, in the order they were added, after the exception.

>>> try:...  raise TypeError('bad type')... except Exception as e:...  e.add_note('Add some information')...  e.add_note('Add some more information')...  raise...Traceback (most recent call last): File "<stdin>", line 2, in <module>TypeError: bad typeAdd some informationAdd some more information>>>

For example, when collecting exceptions into an exception group, we may wantto add context information for the individual errors. In the following eachexception in the group has a note indicating when this error has occurred.

>>> def f():...  raise OSError('operation failed')...>>> excs = []>>> for i in range(3):...  try:...  f()...  except Exception as e:...  e.add_note(f'Happened in Iteration {i+1}')...  excs.append(e)...>>> raise ExceptionGroup('We have some problems', excs) + Exception Group Traceback (most recent call last): | File "<stdin>", line 1, in <module> | ExceptionGroup: We have some problems (3 sub-exceptions) +-+---------------- 1 ---------------- | Traceback (most recent call last): | File "<stdin>", line 3, in <module> | File "<stdin>", line 2, in f | OSError: operation failed | Happened in Iteration 1 +---------------- 2 ---------------- | Traceback (most recent call last): | File "<stdin>", line 3, in <module> | File "<stdin>", line 2, in f | OSError: operation failed | Happened in Iteration 2 +---------------- 3 ---------------- | Traceback (most recent call last): | File "<stdin>", line 3, in <module> | File "<stdin>", line 2, in f | OSError: operation failed | Happened in Iteration 3 +------------------------------------>>>
8. Errors and Exceptions (2024)

FAQs

What are errors and exceptions? ›

The general meaning of exception is a deliberate act of omission while the meaning of error is an action that is inaccurate or incorrect. In Java, Exception, and Error both are subclasses of the Java Throwable class that belongs to java. lang package. But there exist some significant differences between them.

What is the KeyError exception? ›

KeyError is an exception that occurs when you try to access a key that does not exist in a dictionary. KeyError is a type of LookupError that is raised when a key or index used on a mapping or sequence is invalid.

What are exceptions in Python? ›

Python Logical Errors (Exceptions)

Errors that occur at runtime (after passing the syntax test) are called exceptions or logical errors. For instance, they occur when we. try to open a file(for reading) that does not exist ( FileNotFoundError ) try to divide a number by zero ( ZeroDivisionError )

What are errors examples? ›

An error may be defined as the difference between the measured and actual values. For example, if the two operators use the same device or instrument for measurement. It is not necessary that both operators get similar results. The difference between the measurements is referred to as an ERROR.

What are the three 3 types of errors? ›

Types of Errors
  • (1) Systematic errors. With this type of error, the measured value is biased due to a specific cause. ...
  • (2) Random errors. This type of error is caused by random circ*mstances during the measurement process.
  • (3) Negligent errors.

What is the type error exception in Python? ›

TypeError is one of the Exceptions in Python. Whenever we make a call or access any object which does not exist or is unsupported then the TypeError exception occurs. For example, if we try to multiply(*) two strings then the TypeError exception would occur.

How to resolve a key error? ›

How to Fix KeyError in Python. To avoid the KeyError in Python, keys in a dictionary should be checked before using them to retrieve items. This will help ensure that the key exists in the dictionary and is only used if it does, thereby avoiding the KeyError . This can be done using the in keyword.

What are key error lists in Python? ›

There are several common causes of KeyError in Python, including,
  • Typos. ...
  • Case sensitivity. ...
  • Use of wrong data structure. ...
  • Using the Try-Except block. ...
  • Using the get() method. ...
  • Checking if a key exists in a dictionary before accessing it. ...
  • Use of defaultdict. ...
  • Use of setdefault()

What are the 3 errors in Python? ›

There are three basic types of errors that programmers need to be concerned about: Syntax errors, runtime errors, and Logical errors.

How to throw an exception in Python? ›

Throwing exceptions in Python can be done using the raise statement. This can help halt execution when a specific undesired condition is met and provides you with a way to output a clear error message. You can even create your own custom exceptions by creating a new class and inheriting from the base Exception class.

What is the difference between an error and an exception? ›

Key Differences Between Errors and Exceptions

Errors indicate unrecoverable system issues beyond program control. In contrast, exceptions represent unexpected events within the program that can often be handled gracefully.

What are exceptions in coding? ›

An exception is an unexpected behavior (wrong or not) that occurs during software execution. This can interrupts the normal flow of execution and needs proper handling. These “unexpected behaviors” may be in methods of your own software or third-party libraries/components.

What are KeyError exceptions in Python? ›

The Python KeyError is a type of LookupError exception and denotes that there was an issue retrieving the key you were looking for. When you see a KeyError , the semantic meaning is that the key being looked for could not be found.

What is the difference between type error and exception? ›

TypeError is one among the several standard Python exceptions. TypeError is raised whenever an operation is performed on an incorrect/unsupported object type. For example, using the + (addition) operator on a string and an integer value will raise a TypeError.

Why is an error called an exception? ›

The term "exception" is preferred to "error" because it does not imply that anything is wrong - a condition viewed as an error by one procedure or programmer may not be viewed that way by another.

What are bugs errors and exceptions? ›

It is important to distinguish exceptions from bugs and errors. A bug is a programmer mistake that should be fixed before the code is made available to users. An exception is usually not the result of a programmer mistake (though such mistakes can also raise exceptions).

Is an exception always an error? ›

Exceptions are expected failures, which we should recover from. Errors are unexpected failures. By definition, we cannot recover elegantly from unexpected failures.

References

Top Articles
Latest Posts
Article information

Author: Fr. Dewey Fisher

Last Updated:

Views: 5809

Rating: 4.1 / 5 (42 voted)

Reviews: 81% of readers found this page helpful

Author information

Name: Fr. Dewey Fisher

Birthday: 1993-03-26

Address: 917 Hyun Views, Rogahnmouth, KY 91013-8827

Phone: +5938540192553

Job: Administration Developer

Hobby: Embroidery, Horseback riding, Juggling, Urban exploration, Skiing, Cycling, Handball

Introduction: My name is Fr. Dewey Fisher, I am a powerful, open, faithful, combative, spotless, faithful, fair person who loves writing and wants to share my knowledge and understanding with you.