Overview
Exceptions is Section 2 of the PCAP-31-03 syllabus, with two objectives. Handling errors using Python-defined exceptions covers try and except blocks, the order of except branches, except ... as, grouping several exceptions in one branch, the built-in exception hierarchy, raise with and without an argument, assert, the args property of exception objects, and the else and finally clauses. Extending the exceptions hierarchy covers defining your own exception classes and fitting them into the existing tree so that broader handlers still catch them.
The section is small in objectives but dense in rules. Every item turns on control flow: which branch Python selects, whether a later branch is reachable, and which clauses run after the error is handled. Knowing the parent of each common built-in exception, such as ArithmeticError for ZeroDivisionError and LookupError for IndexError and KeyError, settles many questions before you read the options.
How it's tested
Section 2 items present try statements with two or more except branches, sometimes with else and finally, and ask what is printed. Others show a class hierarchy of custom exceptions and ask which handler catches a raised instance, or what e.args holds. Reading the branches strictly top to bottom is the core habit the exam rewards.
-
First matching branch
Several except branches could match, and you pick the first one in source order whose class is the raised type or its ancestor.
-
Clause sequencing
A try block has else and finally, and you decide which clauses run for the error and no-error paths.
-
Custom subclass catch
A user-defined exception inherits from another, and you identify which handler catches it and what its args contain.
A try block runs int('x') and has except Exception first, then except ValueError. int('x') raises ValueError, which is a subclass of Exception, so the first branch matches and handles it. The ValueError branch can never run for this error. Picking the specific handler because it names the exact class is the mistake; Python checks branches in order and stops at the first match.
Objectives 2
Official objectives from the OpenEDG Python Institute outline, in outline order.
2.1 Handle errors using Python-defined exceptionstry/except, branch order, except ... as, grouped exceptions, hierarchy, raise, assert, args, else and finally.
- What it means
- This objective covers the full handling toolkit for built-in exceptions: catching them, ordering handlers, binding the exception object, grouping exception types, re-raising, assertions, reading args, and running code after success or always.
- What to understand
- Python tests except branches from top to bottom and runs only the first one that matches the raised class or one of its ancestors. A tuple such as except (TypeError, ValueError) catches either type. except ... as e binds the instance, whose args attribute is a tuple of constructor arguments. A bare raise inside a handler re-raises the current exception. assert condition raises AssertionError when the condition is false. else runs only when the try block raised nothing; finally always runs.
- How it shows up
- Expect output-prediction items with nested or ordered handlers and questions about whether else or finally executes.
- Common confusion
- Believing Python searches for the most specific handler; it takes the first matching branch in source order.
2.2 Extend the exceptions hierarchy with self-defined exceptionsDefining custom exceptions and integrating them into existing hierarchies.
- What it means
- This objective covers creating exception classes by subclassing Exception or a more specific built-in, and arranging them so that handlers for a parent class also catch the children.
- What to understand
- A custom exception is an ordinary class that inherits from Exception, for example class StockError(Exception): pass. Subclassing a built-in such as ValueError makes existing except ValueError handlers catch your error too. Overriding __init__ and calling super().__init__(message) keeps args and the printed message correct. A handler written for the base custom class catches every subclass raised beneath it, so base-class handlers belong after the specific ones.
- How it shows up
- Items show a small custom hierarchy and ask which except branch catches a raised subclass instance.
- Common confusion
- Subclassing BaseException for application errors; that bypasses except Exception handlers, which is rarely intended.
High-yield concepts
The terms, rules and formulas this domain turns into questions most often.
-
Branch order
Python runs the first except branch that matches the raised exception.
- Remember
- Specific handlers must come before general ones.
- Tested as
- Most output items in this section.
- Trap
- Expecting a later, more specific branch to win.
-
Grouped exceptions
One except clause can catch several types listed in a tuple.
- Remember
- Parentheses are required: except (A, B):
- Tested as
- Syntax and selection items.
- Trap
- Writing except A, B without parentheses.
-
except ... as e
Binds the exception instance to a name inside the handler.
- Remember
- The name is removed after the handler ends.
- Tested as
- Questions that print e or e.args.
- Trap
- Using e after the except block.
-
args
Tuple holding the arguments passed to the exception constructor.
- Remember
- ValueError('a', 1).args is ('a', 1).
- Tested as
- Output items printing e.args.
- Trap
- Expecting a string instead of a tuple.
-
Bare raise
Re-raises the exception currently being handled.
- Remember
- Valid only while an exception is active.
- Tested as
- Propagation questions.
- Trap
- Thinking it raises a new generic Exception.
-
assert
Raises AssertionError when its expression is false.
- Remember
- An optional message becomes the args value.
- Tested as
- Questions on which exception appears.
- Trap
- Expecting ValueError or no error.
-
else clause
Runs only when the try block finishes without raising.
- Remember
- It is skipped whenever an exception occurred.
- Tested as
- Clause sequencing items.
- Trap
- Running else after a handled exception.
-
finally clause
Runs whether or not an exception occurred.
- Remember
- It runs even if the try block returns.
- Tested as
- Clause sequencing items.
- Trap
- Skipping finally after a return.
-
BaseException vs. Exception
BaseException is the root; Exception is the parent of most errors.
- Remember
- KeyboardInterrupt and SystemExit sit directly under BaseException.
- Tested as
- Hierarchy questions.
- Trap
- Assuming except Exception catches every error.
-
ArithmeticError
Parent of ZeroDivisionError, OverflowError and FloatingPointError.
- Remember
- except ArithmeticError catches division by zero.
- Tested as
- Hierarchy and branch order items.
- Trap
- Thinking ZeroDivisionError derives directly from Exception.
-
LookupError
Parent of IndexError and KeyError.
- Remember
- One LookupError handler covers both.
- Tested as
- Hierarchy questions.
- Trap
- Placing KeyError under ValueError.
-
Custom exception class
A user-defined class inheriting from Exception or a subclass.
- Remember
- Handlers for any ancestor catch it.
- Tested as
- Custom hierarchy items.
- Trap
- Forgetting that parent handlers catch children.
Side by side
Concepts candidates mix up, compared on the point that decides the answer.
Clauses of a try statement
| Concept | Meaning | Key difference | Common trap |
|---|---|---|---|
| try | Code that might raise | Stops at the first raised exception | Assuming later lines in try still run |
| except | Handles a matching exception | First match in order wins | Expecting several branches to run |
| else | Runs if try raised nothing | Skipped after any exception | Running it after a handled error |
| finally | Cleanup that always runs | Runs on success, error and return | Skipping it after return |
Raising mechanisms
| Concept | Meaning | Key difference | Common trap |
|---|---|---|---|
| raise ValueError('x') | Raises a new exception instance | args holds ('x',) | Thinking args is the string 'x' |
| raise | Re-raises the active exception | Only valid inside a handler | Using it outside any handler |
| assert cond, msg | Raises AssertionError if cond is false | msg becomes args | Expecting a different exception type |
Common built-in families
| Concept | Meaning | Key difference | Common trap |
|---|---|---|---|
| ArithmeticError | Math failures | Parent of ZeroDivisionError | Missing it as a catch-all for division |
| LookupError | Failed index or key lookups | Parent of IndexError and KeyError | Confusing it with ValueError |
| BaseException-only | System-level signals | KeyboardInterrupt and SystemExit | Expecting except Exception to catch them |
Exam traps
Each trap is an answer that looks right. Learn the clue that should change your mind.
-
Specific handler wins
- What candidates pick
- Pick the output of the ZeroDivisionError branch when ArithmeticError is listed first.
- Why it looks right
- The exact class name matches the error.
- Why it's wrong
- Python stops at the first matching branch, and ArithmeticError is an ancestor of ZeroDivisionError.
Clue to watch for A parent class appears above its child in the except list.
-
else after handling
- What candidates pick
- Include else output after an exception was caught.
- Why it looks right
- The handler resolved the problem.
- Why it's wrong
- else runs only if the try block raised nothing at all.
Clue to watch for The try block contains an operation that fails.
-
Return skips finally
- What candidates pick
- Leave out finally output because try returned first.
- Why it looks right
- return normally exits the function immediately.
- Why it's wrong
- finally runs before the function actually returns, even after a return statement.
Clue to watch for A return sits inside try with a finally clause below.
-
args is the message
- What candidates pick
- Choose 'error' as the output of print(e.args).
- Why it looks right
- The message looks like the only value.
- Why it's wrong
- args is always a tuple, so the output is ('error',) with the trailing comma.
Clue to watch for The code prints e.args rather than e.
-
Tuple without parentheses
- What candidates pick
- Accept except TypeError, ValueError: as valid grouping.
- Why it looks right
- Commas separate items elsewhere in Python.
- Why it's wrong
- Python 3 requires a parenthesized tuple to catch several types in one clause.
Clue to watch for Options differ only in the presence of parentheses.
-
Custom error escapes
- What candidates pick
- Say an uncaught error occurs when except Exception follows raise MyError.
- Why it looks right
- MyError is not a built-in type.
- Why it's wrong
- A class derived from Exception is caught by except Exception like any built-in subclass.
Clue to watch for The custom class definition shows Exception as its base.
Answer framework
For a Section 2 snippet, follow these steps to trace control flow the way PCAP-31-03 expects.
- Find the first line in the try block that raises, and name the exact exception class it produces, such as ZeroDivisionError for 1 / 0 or ValueError for int('x').
- Walk the except branches from top to bottom and stop at the first whose class is that type or one of its ancestors.
- If no branch matches, the exception propagates outward after finally runs, so check enclosing try statements or expect a traceback.
- Decide whether else runs: only when the try block raised nothing, never after a handled error.
- Add the finally output last, and remember it runs even when the try or handler executes return or raises again.
Practice question
Want more like this? The PCAP practice test has questions for every domain.
Checklist
0 of 11
Tick each one you can do without notes. Your ticks stay in this browser.
Study strategy
Start by drawing the part of the hierarchy PCAP uses: BaseException at the top, Exception beneath it, then ArithmeticError with ZeroDivisionError, LookupError with IndexError and KeyError, and the standalone ValueError, TypeError and AssertionError. Put KeyboardInterrupt and SystemExit beside Exception, not under it. Keep the drawing next to you while practicing.
Then write small try statements in the interpreter and change one thing at a time: swap the order of handlers, remove the failing line, add a return inside try, add else and finally. Predict the output before running each version. This trains the top-to-bottom reading that the exam rewards.
Move on to raise and assert. Raise built-in exceptions with one, two and zero arguments and print args each time. Re-raise inside a handler with a bare raise and watch the traceback. Trigger an assert with and without a message.
Finish with custom exceptions. Build a base class derived from Exception and two subclasses, raise each, and test which handlers catch them. Then derive one class from ValueError and confirm that an existing ValueError handler catches it.
FAQ
How much of PCAP is Section 2, Exceptions?
Exceptions is 14% of PCAP-31-03, and the official syllabus assigns it 5 of the 40 exam items.
Does Python pick the most specific except branch?
No. It checks branches in the order written and runs the first one whose class matches the exception or one of its ancestors.
When does the else clause run?
Only when the try block completes without raising any exception. A handled exception still means else is skipped.
What is the args property?
A tuple of the arguments passed to the exception's constructor. An exception created with one string has a one-element tuple.
Why should custom exceptions inherit from Exception?
Handlers written as except Exception then catch them, while system signals such as KeyboardInterrupt stay outside that net.
What does a bare raise do?
Inside an except block it re-raises the exception currently being handled, preserving its type and traceback.
Does assert run in every situation?
Normally yes, but assertions are removed when Python runs with the -O optimization flag, so they suit checks during development rather than input validation.
Test your Domain 2 knowledge
You have covered except ordering, else and finally, raise and assert, args and custom exception classes. Test whether you can trace every branch correctly in timed questions.