Exception Types, try, except, else, and finally

Key Takeaways

  • A try block holds code that may raise; matching except clauses decide whether execution recovers.
  • Except clauses are tested top to bottom, so specific handlers must precede broad ones like Exception.
  • The else clause runs only when the try block completes with no exception raised.
  • The finally clause runs on every path (success, handled error, or unhandled error) and is used for cleanup.
  • Core PCEP exception types are NameError, TypeError, ValueError, IndexError, KeyError, and ZeroDivisionError.
Last updated: June 2026

What an exception changes

An exception interrupts the normal statement-by-statement flow. If code in a try block raises, Python abandons the rest of the try block and searches the attached except clauses from top to bottom. If a clause matches the exception's class, that handler runs. If none matches, the exception propagates outward and may crash the program.

try:
    n = int('8')
    print(10 / n)
except ValueError:
    print('bad number')
except ZeroDivisionError:
    print('zero')

The conversion int('8') succeeds (n is 8), the division succeeds, and no exception is raised, so no handler runs. The snippet prints 1.25. Note the key detail: once int('8') had failed, print(10 / n) would never have executed, because Python stops the try block at the first failing statement.

The six exception types PCEP expects

ExceptionTypical cause in exam snippets
NameErrorReading a name that is not defined in any scope
TypeErrorWrong operand type, or wrong function arguments
ValueErrorRight type, invalid value, e.g. int('abc')
IndexErrorList, tuple, or string index out of range
KeyErrorMissing dictionary key with bracket lookup
ZeroDivisionErrorDivision or modulo by zero

The TypeError versus ValueError split is heavily tested. int(3.5) works because the type (float) is acceptable. int('abc') raises ValueError: strings are an acceptable type for int() in general, but that particular string cannot be parsed.

Collection errors follow the same logic. letters[9] raises IndexError because integer indexing is valid in general but position 9 does not exist. record['age'] raises KeyError because bracket key lookup is valid but that key is absent. Recognizing why the type is right but the value/position is wrong is what the exam rewards.

Handler order is significant

Except clauses are tested in the order written. A broad handler placed first catches the exception before any later, more specific handler gets a chance.

try:
    values = [1, 2]
    print(values[5])
except Exception:
    print('general')
except IndexError:
    print('index')

This prints general, not index. Because IndexError is a subclass of Exception, the first matching clause wins and the specific clause is dead code. Correct ordering puts except IndexError before except Exception.

You can also catch several types in one clause with a tuple:

try:
    x = int('z')
except (ValueError, TypeError):
    print('input problem')

The parentheses are required; except ValueError, TypeError: is invalid syntax in Python 3. This prints input problem because int('z') raises ValueError, which the tuple includes.

else, finally, and continuation

The else clause runs only if the try block completes with no exception. The finally clause runs on every path, used for cleanup like closing files.

try:
    item = {'a': 1}['b']
except KeyError:
    print('missing')
else:
    print('found')
finally:
    print('done')

The lookup raises KeyError. The except prints missing, else is skipped (an exception occurred), and finally prints done.

When an exception is handled, execution resumes after the whole try statement:

try:
    print(int('x'))
except ValueError:
    print('handled')
print('after')

The output is handled then after; the inner print never completed because int('x') failed first. Exam routine: (1) find the first try statement that can fail, (2) name its exact exception class, (3) pick the first matching except, (4) decide whether else runs, (5) note what finally prints. This stops the two classic errors: running statements after the failing line, and choosing the most specific handler instead of the first matching one.

Capturing the exception object and the exception hierarchy

You can bind the raised exception to a name using as, which lets a snippet print the message:

try:
    print(10 / 0)
except ZeroDivisionError as e:
    print('error:', e)

This prints something like error: division by zero. The name e exists only inside the except block; PCEP may ask whether e is available after the try statement (in Python 3 it is deleted when the block ends).

Built-in exceptions form a class hierarchy, and that ordering is exactly why broad handlers can swallow specific ones. A simplified view of the part PCEP tests:

BaseException
 └── Exception
      ├── ArithmeticError
      │    └── ZeroDivisionError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── NameError
      │    └── UnboundLocalError
      ├── TypeError
      └── ValueError

Two practical consequences appear on the exam. First, except LookupError: catches both IndexError and KeyError, because both are subclasses of LookupError. Second, except Exception: catches essentially every ordinary runtime error, which is why placing it first makes later specific clauses unreachable.

Raising your own exception. The raise keyword triggers an exception deliberately: raise ValueError('too big'). A bare raise inside an except block re-raises the current exception so an outer handler can see it. If a snippet raises inside an except clause and no outer handler catches it, the program crashes after any finally has run. Trace handler bodies as carefully as the original try block, since a second failure there changes the outcome.

A final reusable rule: a finally block runs even when the try block contains a return. The finally executes first, and if finally itself contains a return, that value overrides the one from the try block, a subtle item that occasionally appears in scenario questions. When in doubt, remember finally always gets the last word before control leaves the try statement.

Test Your Knowledge

Which exception is most likely raised by int('abc')?

A
B
C
D
Test Your Knowledge

Why should except IndexError usually appear before except Exception in a try statement?

A
B
C
D
Test Your Knowledge

When does the else clause of a try statement execute?

A
B
C
D