Study guide
3.2 The Built-in Exception Hierarchy
OpenEDG PCAP — Certified Associate in Python Programming Exam
Track your progress as you read
Finished sections get a check mark.
1 Chapter 1: The PCAP-31-03 Exam Blueprint and Test-Day Logistics
1.1 The PCAP-31-03 Blueprint, Scoring, and Exam-Day Logistics
2 Chapter 2: Modules, Packages, and the Standard Library
2.1 Module Imports and Namespace Mechanics 2.2 Module Construction and Execution 2.3 Package Hierarchy and Navigation 2.4 Standard Library Modules and Pip
3 Chapter 3: Exceptions and Error Handling
3.1 Exception Control Flow and Syntax 3.2 The Built-in Exception Hierarchy 3.3 Raising Exceptions and Assertions 3.4 Custom Exceptions and Exception Chaining
4 Chapter 4: Strings, Encodings, and Text Processing
4.1 Character Encodings and String Immutability 4.2 String Indexing, Slicing, and Comparison 4.3 String Inspection and Classification Methods 4.4 String Transformation and Formatting Methods 4.5 Iterating, Sorting, and Comparing Strings Against Other Types
5 Chapter 5: Object-Oriented Programming Fundamentals
5.1 Classes, Instances, and Attributes 5.2 Encapsulation, Privacy, and Name Mangling 5.3 Dunder Methods and Object Lifecycle 5.4 Discovering Class Structure: __name__, __module__, __bases__, and Identity
6 Chapter 6: Advanced OOP, Inheritance, and Metaprogramming
6.1 Single Inheritance, Method Overriding, and Polymorphism 6.2 Multiple Inheritance and Method Resolution Order (MRO) 6.3 Class Methods, Static Methods, and Properties
7 Chapter 7: Functional Python, Comprehensions, and Closures
7.1 List, Dictionary, and Set Comprehensions 7.2 Lambda Expressions and Higher-Order Functions 7.3 Variable Scopes, the LEGB Rule, and Closures
8 Chapter 8: Iterators, Generators, and File I/O
8.1 Iterators and the Iteration Protocol 8.2 Generator Functions and Generator Expressions 8.3 File Input/Output and Context Managers 8.4 Predefined Streams, Handles vs. Streams, and errno Diagnostics
3.2 The Built-in Exception Hierarchy
Key Takeaways Explain This Topic AI
All built-in exceptions form an inheritance hierarchy rooted at BaseException, with standard application errors inheriting from Exception.
SystemExit, KeyboardInterrupt, and GeneratorExit inherit directly from BaseException so that catching Exception will not block normal exit signals or Ctrl+C.
ArithmeticError is the base class for ZeroDivisionError, OverflowError, and FloatingPointError.
LookupError is the parent class for both IndexError (sequence subscripting) and KeyError (dictionary key lookups).
Exception matching operates polymorphically: catching a parent class in an except block intercepts all current and future derived subclasses.
Last updated: August 2026
The Built-in Exception Hierarchy
In Python, all exceptions are regular Python objects instantiated from classes organized in a strictly defined inheritance tree. When an error occurs, Python uses standard object-oriented polymorphism to match the raised exception instance against the classes specified in except clauses. Mastering this hierarchy is vital for writing precise exception handlers and answering classification questions on the PCAP exam.
The Root Architecture: BaseException vs Exception
At the root of the entire exception system sits BaseException . However, Python intentionally splits its root hierarchy into two distinct functional categories. BaseException
- ├── SystemExit
- ├── KeyboardInterrupt
- ├── GeneratorExit
- └── Exception
- ├── ArithmeticError
- │ ├── FloatingPointError
- │ ├── OverflowError
- │ └── ZeroDivisionError
- ├── LookupError
- │ ├── IndexError
- │ └── KeyError
- ├── TypeError
- ├── ValueError
- ├── AttributeError
- ├── NameError
- │ └── UnboundLocalError
- ├── ImportError
- │ └── ModuleNotFoundError
- ├── OSError
- │ ├── FileNotFoundError
- │ ├── PermissionError
- │ ├── IsADirectoryError
- │ └── FileExistsError
- └── SyntaxError
- └── IndentationError
- └── TabError
- Why BaseException Exists Separately from Exception
Python distinguishes between system-exiting events and application-level errors :
SystemExit : Raised by sys.exit() when a program requests termination.
KeyboardInterrupt : Raised when the user sends an interrupt signal (such as typing Ctrl+C ).
GeneratorExit : Raised inside a generator when its close() method is called.
Exception : The base class for all non-system-exiting, user-handleable application exceptions.
Important
The Broad Catch Rule: User code should almost always catch except Exception: , never except BaseException: . If you catch BaseException (or use a bare except: ), your program will trap KeyboardInterrupt and SystemExit , making it impossible for users to terminate the script via Ctrl+C or standard system signals. # BAD PRACTICE: Traps Ctrl+C and sys.exit()
try:
- run_server()
- except BaseException: # Or bare 'except:'
- print("Ignored exit signal!")
# GOOD PRACTICE: Catches application errors, allows clean termination
try:
run_server()
except Exception as err:
- logger.error(f"Application error: {err}")
- Major Built-in Exception Families
Let us analyze the major built-in exception families tested on the PCAP exam.
1. ArithmeticError Family
ArithmeticError is the common base class for mathematical calculation errors:
ZeroDivisionError : Raised when the second argument of a division ( / , // ) or modulo ( % ) operation is zero across integer, float, or Decimal types.
OverflowError : Raised when an arithmetic operation produces a numeric result too large to be represented. Note: In Python 3, integers have arbitrary precision and will not raise OverflowError during standard addition or exponentiation; however, floating-point numbers have fixed 64-bit IEEE 754 precision and raise OverflowError on operations like math.exp(1000) or 2.0 ** 2000 .
FloatingPointError : Raised when a floating-point operation fails and hardware floating-point exception traps are configured. import math
try:
val = math.exp(1000) # Float calculation exceeds IEEE 754 limit
except ArithmeticError as e:
- print(f"Caught arithmetic error: {type(e).__name__}")
- # Output: Caught arithmetic error: OverflowError
- 2. LookupError Family
LookupError is the base class for errors that occur when a key or index used to access a collection is invalid:
IndexError : Raised when a sequence subscript is out of range (e.g. accessing index 5 of a 3-element list or string).
KeyError : Raised when a mapping (dictionary) key is not found in the set of existing keys. def safe_lookup(collection, key_or_idx):
try:
return collection[key_or_idx]
except LookupError as err:
return f"Lookup failed: {type(err).__name__}"
- print(safe_lookup([10, 20, 30], 99)) # Output: Lookup failed: IndexError
- print(safe_lookup({'a': 1}, 'z')) # Output: Lookup failed: KeyError
- 3. TypeError vs ValueError
Distinguishing between TypeError and ValueError is one of the most frequently tested concepts:
Exception Formal Definition Real-World Trigger Examples
TypeError An operation or function is applied to an object of inappropriate type . 'hello' + 5 ; len(1234) ; [1, 2][1.5]
ValueError A function receives an argument that has the correct data type but an inappropriate value . int('abc') (str is correct type, but 'abc' is not digits); math.sqrt(-10) (int is correct type, but negative is invalid)
4. NameError and UnboundLocalError
NameError : Raised when a local or global name is not found in the active namespaces.
UnboundLocalError : A direct subclass of NameError . Raised when a reference is made to a local variable in a function, but no value has been assigned to that variable yet. x = 10
def modify():
- print(x) # UnboundLocalError: local variable 'x' referenced before assignment
- x = 20
Because modify contains the assignment x = 20 , Python marks x as local to the entire function scope. The print(x) statement tries to read the local x before the assignment executes.
5. AttributeError
Raised when an attribute reference or assignment fails on an object (e.g. calling a nonexistent method 'hello'.push(10) or accessing math.nonexistent_constant ).
6. ImportError and ModuleNotFoundError
ModuleNotFoundError : A subclass of ImportError , raised when an import statement cannot locate the specified module file.
ImportError : Raised when the module file is located, but a specific name cannot be imported from it (e.g. from math import nonexistent_func ).
7. OSError and File System Exceptions
OSError represents operating-system-level errors. In modern Python 3, many older exceptions ( IOError , EnvironmentError ) were merged under OSError , which has concrete subclasses:
FileNotFoundError : Attempting to read a nonexistent file path.
PermissionError : Insufficient filesystem access rights.
IsADirectoryError : Attempting file operations on a folder.
FileExistsError : Attempting to create an already existing file with exclusive mode ( 'x' ).
8. Compile-time vs Runtime Exceptions: SyntaxError
SyntaxError occurs when the Python parser encounters invalid code grammar during the compilation/parsing phase. Subclasses include IndentationError and TabError .
Note
A SyntaxError within the same file cannot be caught by a try block in that same file because Python fails to parse the script before execution begins. However, a SyntaxError can be caught at runtime if it is generated dynamically via eval() , exec() , or importlib.import_module() .
Polymorphic Catch Mechanics
Because exception matching is implemented via issubclass() , an except clause specifying a parent class intercepts instances of that parent class as well as all descendant classes. # Demonstration of Polymorphic Matching
- print(issubclass(ZeroDivisionError, ArithmeticError)) # True
- print(issubclass(ZeroDivisionError, Exception)) # True
- print(issubclass(IndexError, LookupError)) # True
- print(issubclass(KeyError, LookupError)) # True
- print(issubclass(UnboundLocalError, NameError)) # True