Try 10 focused PCAP-31-03 questions on Section 2: Exceptions, with explanations, then continue with IT Mastery.
Open the matching IT Mastery practice page for timed mocks, topic drills, progress tracking, explanations, and full practice.
| Field | Detail |
|---|---|
| Exam route | PCAP-31-03 |
| Topic area | Section 2: Exceptions |
| Blueprint weight | 14% |
| Page purpose | Focused sample questions before returning to mixed practice |
Use this page to isolate Section 2: Exceptions for PCAP-31-03. Work through the 10 questions first, then review the explanations and return to mixed practice in IT Mastery.
| Pass | What to do | What to record |
|---|---|---|
| First attempt | Answer without checking the explanation first. | The fact, rule, calculation, or judgment point that controlled your answer. |
| Review | Read the explanation even when you were correct. | Why the best answer is stronger than the closest distractor. |
| Repair | Repeat only missed or uncertain items after a short break. | The pattern behind misses, not the answer letter. |
| Transfer | Return to mixed practice once the topic feels stable. | Whether the same skill holds up when the topic is no longer obvious. |
Blueprint context: 14% of the practice outline. A focused topic score can overstate readiness if you recognize the pattern too quickly, so use it as repair work before timed mixed sets.
These questions are original IT Mastery practice items aligned to this topic area. They are designed for self-assessment and are not official exam questions.
Topic: Section 2: Exceptions
A developer is verifying a standard-library import in a package startup script. What is printed by this code?
try:
import math as m
print(m.sqrt(16))
except ImportError:
print("import failed")
else:
print(m.__name__)
finally:
print("finished")
Options:
A. 4.0, finished
B. math, 4.0, finished
C. 4.0, import failed, finished
D. 4.0, math, finished
Best answer: D
Explanation: The else clause in a try statement runs only when the try block completes with no exception. Here, importing math succeeds and m.sqrt(16) prints 4.0, so the else block prints math, and finally prints finished.
The key concept is that try ... except ... else ... finally has a distinct no-error path. In this code, import math as m succeeds, and print(m.sqrt(16)) prints 4.0. Because no ImportError occurs, the except block is skipped and the else block runs, printing m.__name__, which is math. After that, the finally block always runs and prints finished.
So the execution order is:
try blockexcept because no exception occurredelsefinallyThe closest mistake is assuming else is optional cleanup, but cleanup belongs to finally, not else.
math misses that else runs on the no-exception path.import failed after 4.0 is impossible because the except block does not run when the try block succeeds.math before 4.0 reverses the execution order; the try block prints first, then else, then finally.Topic: Section 2: Exceptions
What is printed by this Python 3 code?
for mode in ("existing", "new"):
saved = None
try:
try:
1 / 0
except ZeroDivisionError as ex:
saved = ex
if mode == "existing":
raise ex
else:
raise ZeroDivisionError("again")
except ZeroDivisionError as err:
print(mode, saved is err)
Options:
A. It prints existing True and then new False.
B. It prints existing True and then new True.
C. It prints existing False and then new True.
D. It prints existing False and then new False.
Best answer: A
Explanation: In the existing pass, raise ex raises the same exception instance that was caught, so saved is err is True. In the new pass, raise ZeroDivisionError("again") creates a different exception object, so the identity test is False.
The key concept is the difference between raising an existing exception object and raising a new one. Inside the inner except, ex refers to the caught ZeroDivisionError instance.
When the code executes raise ex, it raises that same object again. The outer except catches the identical instance, so saved is err evaluates to True.
When the code executes raise ZeroDivisionError("again"), Python creates a fresh exception instance. The outer except still catches a ZeroDivisionError, but it is not the same object stored in saved, so saved is err is False.
The important takeaway is that matching exception type does not mean matching object identity.
True fails because two exceptions of the same type are not automatically the same object.False fails because raise ex does not build a new exception; it raises the caught instance.raise ZeroDivisionError("again"), not by raise ex.Topic: Section 2: Exceptions
A developer wants one handler to catch two specific exception types while allowing another custom subclass to fall through to a later handler. Which statement about this code is correct?
class ParseError(Exception):
pass
class EmptyField(ParseError):
pass
class BadField(ParseError):
pass
def check(kind):
try:
if kind == "empty":
raise EmptyField("name")
elif kind == "bad":
raise BadField("name")
elif kind == "value":
raise ValueError("name")
except (EmptyField, ValueError) as err:
print("group", type(err).__name__, err.args[0])
except ParseError as err:
print("parse", type(err).__name__, err.args[0])
else:
print("ok")
finally:
print("end")
Options:
A. The grouped handler runs for check("empty") and check("value").
B. The finally block runs only when kind causes an exception.
C. The else block runs after check("bad") because the exception is handled.
D. The grouped handler also runs for check("bad") because BadField is a ParseError.
Best answer: A
Explanation: A grouped except clause catches any exception type named in its tuple. In this code, EmptyField and ValueError match the grouped handler, while BadField is handled later by except ParseError because it is not part of the tuple.
Python checks except clauses from top to bottom. A grouped handler like except (EmptyField, ValueError) as err: is chosen when the raised exception is an instance of either listed type. That means check("empty") and check("value") both enter the same handler, and err.args[0] would contain "name".
BadField does not match that tuple, even though it is a subclass of ParseError, so execution continues to the next compatible handler: except ParseError as err:. The else block is separate from exception handling and runs only when the try block finishes without raising any exception. The finally block runs every time, whether an exception occurs or not.
The key takeaway is that a grouped except handles only the types explicitly listed there, not every related type in the hierarchy.
BadField fails because being a ParseError does not make it match the tuple (EmptyField, ValueError).else fails because else runs only when the try block raises no exception at all.finally fails because finally executes after both normal and exceptional flow.Topic: Section 2: Exceptions
A developer uses a custom exception hierarchy to classify validation failures:
class AppError(Exception):
pass
class InputError(AppError):
pass
class EmptyNameError(InputError):
pass
try:
raise EmptyNameError("name is required")
except AppError as err:
print(type(err).__name__)
print(err.__class__.__bases__[0].__name__)
Which statement is correct about what these exception classes represent?
Options:
A. EmptyNameError.__bases__ means the raised object belongs only to InputError, not to EmptyNameError.
B. InputError and AppError are class variables that store details for EmptyNameError objects.
C. except AppError reclassifies the raised object as an AppError instance before assigning it to err.
D. EmptyNameError is the most specific error category, and err is still an instance of it when caught by except AppError.
Best answer: D
Explanation: Exception classes are ordinary classes used to group related error conditions. Here, EmptyNameError names the specific category, while the object bound to err is the actual raised instance and keeps its original class even though a base-class handler catches it.
In Python, an exception class represents a type or category of error, not a single error event. The actual event is the exception object created from that class. In this hierarchy, EmptyNameError is a specialized kind of InputError, which is itself a kind of AppError.
When raise EmptyNameError("name is required") runs, the raised object is an instance of EmptyNameError. The except AppError as err clause catches it because subclass instances also match base-class handlers. That match does not convert the object into an AppError instance.
So type(err).__name__ stays EmptyNameError, while err.__class__.__bases__[0].__name__ shows its immediate parent class, InputError. The key idea is: exception classes classify errors; exception instances represent specific occurrences of those errors.
except AppError only matches by inheritance.InputError and AppError as class variables fails because they are superclass exception types.__bases__ to replace the runtime class fails because __bases__ describes parent classes, not object conversion.Topic: Section 2: Exceptions
A developer expects bad number when invalid input is processed, but that message never appears; for "x" the program prints generic failure instead.
values = ["4", "x"]
for v in values:
try:
print(12 / int(v))
except Exception:
print("generic failure")
except ValueError:
print("bad number")
What is the best fix?
Options:
A. Use raise inside except Exception to let except ValueError run.
B. Replace except Exception with except BaseException.
C. Move int(v) outside the try block.
D. Place except ValueError before except Exception.
Best answer: D
Explanation: Python checks except clauses from top to bottom. Here, int("x") raises ValueError, but except Exception catches it first because ValueError inherits from Exception. The specific handler must come before the general one.
The core rule is exception-handler ordering: Python executes the first except clause whose type matches the raised exception. In this code, int("x") raises ValueError. Because ValueError is part of the Exception hierarchy, the earlier except Exception clause already matches, so the later except ValueError clause is effectively unreachable for that error.
except Exception only as a last resort.A common mistake is assuming Python will keep checking later handlers after entering a broad one, but it does not.
except.BaseException makes the problem worse by catching even more cases before the specific handler.try block from handling the ValueError at all.Topic: Section 2: Exceptions
A utility should return "missing" for either a missing dictionary key or an out-of-range list index. After a refactor, it now ends with an uncaught IndexError:
def get_value(container, key):
try:
return container[key]
except KeyError:
return "missing"
print(get_value(["A", "B"], 5))
Which change is the best fix?
Options:
A. Replace except KeyError with except LookupError.
B. Add finally: return "missing" after the except block.
C. Replace except KeyError with except ArithmeticError.
D. Replace return container[key] with raise KeyError(key).
Best answer: A
Explanation: except matches the named exception class and its subclasses. IndexError is not a subclass of KeyError, but both IndexError and KeyError inherit from LookupError, so catching LookupError handles both cases required by the function.
Python uses the exception hierarchy when deciding whether an except block handles a raised exception. A handler for KeyError catches KeyError and any subclasses of KeyError, but it does not catch sibling exceptions. Here, list access with an invalid index raises IndexError, while missing dictionary access raises KeyError.
Both of those exceptions share the same parent:
LookupErrorKeyErrorIndexErrorSo if one function must handle both failed dictionary lookups and failed sequence indexing, except LookupError is the right common handler. A broader catch like Exception would also work, but it would handle unrelated errors too.
The key idea is that shared parent classes can be used to catch multiple related exception types.
ArithmeticError fails because lookup problems are unrelated to arithmetic exceptions.finally: return "missing" would override normal successful results too.KeyError manually does not fix the hierarchy mismatch; it just forces a different exception.Topic: Section 2: Exceptions
A developer is debugging why a specific handler never runs:
class AppError(Exception):
pass
class ConfigError(AppError):
pass
try:
raise ConfigError("missing file")
except AppError as err:
print("app:", type(err).__name__)
except ConfigError as err:
print("config:", err)
finally:
print("cleanup")
Which change should be made so the ConfigError handler becomes reachable while other AppError exceptions are still handled?
Options:
A. Move except ConfigError as err: above except AppError as err:.
B. Replace finally with else.
C. Change except AppError as err: to except Exception as err:.
D. Re-raise err inside the AppError handler.
Best answer: A
Explanation: Python checks except clauses from top to bottom. Because ConfigError inherits from AppError, the broader AppError handler matches first and the later specific handler is never reached. Reordering them fixes the flow.
In Python, exception handlers are tested in order, and the first matching except block runs. Here, ConfigError is a subclass of AppError, so except AppError as err: already matches the raised ConfigError. That makes the later except ConfigError as err: effectively unreachable.
To preserve specific handling and still catch other related exceptions, order handlers from most specific to most general:
except ConfigError as err:except AppError as err:If one handler runs, Python does not continue searching later except clauses in the same try. The finally block is separate and still executes either way. The key takeaway is to place subclass exception handlers before superclass handlers.
Exception makes the first handler even broader, so the specific handler still cannot run.try.finally with else changes when that block runs, but it does not solve the handler-ordering problem.Topic: Section 2: Exceptions
A developer wants to inspect the values stored in an exception object. What is printed by this Python 3 code?
data = None
try:
raise IndexError("row", 5)
except IndexError as err:
data = err.args
print(data[0], data[1], type(data).__name__)
Options:
A. IndexError: ('row', 5)
B. row 5 list
C. ('row', 5) tuple
D. row 5 tuple
Best answer: D
Explanation: In an except ... as block, the name after as refers to the exception object. Its args property stores the positional arguments passed when the exception was raised, and that value is a tuple.
When raise IndexError("row", 5) executes, Python creates an IndexError object with two positional arguments. Inside except IndexError as err, err is that exception instance, and err.args contains those arguments as a tuple: ("row", 5).
The code assigns that tuple to data, then prints:
data[0] → rowdata[1] → 5type(data).__name__ → tupleSo the printed result is row 5 tuple. The closest trap is confusing err.args with printing the exception object itself, which would show the tuple representation instead of separate indexed values.
data, not data[0] and data[1] separately.args are stored in a tuple, not a list.except IndexError block catches the raised exception.Topic: Section 2: Exceptions
Consider this code. Which statement correctly identifies the handled exception and the exception that propagates beyond the try/except statement?
from math import sqrt
try:
print(sqrt(-1))
except ImportError:
print("import")
except ValueError:
print("value")
print(math.pi)
Options:
A. ValueError is handled, then NameError propagates.
B. ValueError propagates because the first except does not match.
C. ImportError is handled, then NameError propagates.
D. ValueError is handled, then the program ends normally.
Best answer: A
Explanation: The call sqrt(-1) raises a ValueError, and that exception is handled by the matching except ValueError clause. After the try/except finishes, print(math.pi) runs outside it, and because only sqrt was imported, math is undefined, so a NameError propagates.
This tests the difference between an exception handled inside a try/except block and one raised later with no matching handler. In from math import sqrt, only the name sqrt is added to the current namespace; the name math is not.
Execution goes like this:
sqrt(-1) raises ValueError.except ValueError catches it and prints value.try/except block.print(math.pi) then raises NameError because math was never imported as a module name.So the ValueError is handled, but the later NameError is not. The closest mistake is assuming that importing one member from a module also defines the module’s qualified name.
ImportError is handled confuses a successful import with the later runtime error from sqrt(-1).from math import sqrt does not define the name math.ValueError propagates misunderstands handler matching; except order matters for subclasses, not for unrelated exceptions here.Topic: Section 2: Exceptions
A developer adds a custom exception so existing lookup-related handlers keep working. What is printed by this Python 3 code?
class MissingKeyError(KeyError):
pass
def fetch(data, key):
if key not in data:
raise MissingKeyError(key)
return data[key]
try:
print(fetch({"x": 1}, "y"))
except LookupError:
print("lookup")
except Exception:
print("other")
Options:
A. lookup
B. MissingKeyError traceback
C. y
D. other
Best answer: A
Explanation: Exception handlers match subclasses as well as the exact named class. Because MissingKeyError extends KeyError, and KeyError is a LookupError, the existing except LookupError block catches it and prints lookup.
In Python, an except clause handles instances of the named exception class and any of its subclasses. Here, the custom MissingKeyError is integrated into the built-in hierarchy by inheriting from KeyError. Since KeyError is a subclass of LookupError, raising MissingKeyError also satisfies except LookupError.
When fetch({"x": 1}, "y") runs, the key is missing, so the function raises MissingKeyError before returning any value. That means print(fetch(...)) never prints a dictionary value. The generic except Exception block is not reached because Python uses the first matching handler.
other is tempting because Exception is a superclass, but the earlier LookupError handler already matches.y would require the function to return a value, but it raises an exception before any return occurs.except block when a superclass handler already covers it.Use the PCAP-31-03 Practice Test page for the full IT Mastery route, mixed-topic practice, timed mock exams, explanations, and web/mobile app access.
Try PCAP-31-03 on Web View PCAP-31-03 Practice Test
Read the PCAP-31-03 Cheat Sheet on Tech Exam Lexicon, then return to IT Mastery for timed practice.