Error Handling Quiz
Quiz
Question 1 of 34
(0 answered)
Question 1
What happens when an exception occurs in a try block and is caught by an except block, followed by an else clause?
✓
Correct!
The else clause only executes if no exception occurs in the try block. If an exception is caught by except, the else block is skipped. Option C describes
finally, not else. Option D reverses the logic — unhandled (propagating) exceptions skip else too.✗
Incorrect
The else clause only executes if no exception occurs in the try block. If an exception is caught by except, the else block is skipped. Option C describes
finally, not else. Option D reverses the logic — unhandled (propagating) exceptions skip else too.Think about the purpose of the else clause - when does it run?
Question 2
The finally block executes only if an exception occurs in the try block.
✓
Correct!
The finally block always executes, whether an exception occurs or not. This makes it perfect for cleanup operations like closing files or releasing resources.
✗
Incorrect
The finally block always executes, whether an exception occurs or not. This makes it perfect for cleanup operations like closing files or releasing resources.
Consider what ‘finally’ means in everyday language.
Question 3
Which of the following are valid reasons to use a finally block?
✓
Correct!
The finally block is for cleanup and actions that must always run. Handling exceptions belongs in except blocks. Preventing exception propagation requires returning True from
__exit__ or using contextlib.suppress — finally does not suppress exceptions.✗
Incorrect
The finally block is for cleanup and actions that must always run. Handling exceptions belongs in except blocks. Preventing exception propagation requires returning True from
__exit__ or using contextlib.suppress — finally does not suppress exceptions.Think about operations that must happen regardless of success or failure.
Question 4
Arrange the exception handling blocks in their correct execution order:
Drag to arrange in the order Python executes them
⋮⋮
try block
⋮⋮
else block (if no exception)
⋮⋮
except block (if exception occurs)
⋮⋮
finally block
✓
Correct!
Python executes: try → except (if exception) → else (if no exception) → finally (always). The finally block runs last, regardless of what happened before.
✗
Incorrect
Python executes: try → except (if exception) → else (if no exception) → finally (always). The finally block runs last, regardless of what happened before.
Question 5
What gets printed when this code runs?
try:
x = 10 / 2
except ZeroDivisionError:
print("Error")
else:
print("Success")
finally:
print("Done")What will this code output?
✓
Correct!
No exception occurs (10/2 is valid), so except is skipped, else executes printing ‘Success’, then finally always executes printing ‘Done’.
✗
Incorrect
No exception occurs (10/2 is valid), so except is skipped, else executes printing ‘Success’, then finally always executes printing ‘Done’.
Trace through each block - does 10/2 raise an exception?
Question 6
In Python’s exception hierarchy, what is the relationship between Exception and ZeroDivisionError?
✓
Correct!
ZeroDivisionError → ArithmeticError → Exception → BaseException. Option A is the almost-right trap — ZeroDivisionError is under Exception, but via ArithmeticError. Skipping intermediate classes matters when you want to catch all arithmetic errors at once.
✗
Incorrect
ZeroDivisionError → ArithmeticError → Exception → BaseException. Option A is the almost-right trap — ZeroDivisionError is under Exception, but via ArithmeticError. Skipping intermediate classes matters when you want to catch all arithmetic errors at once.
Look at the exception hierarchy diagram in the content.
Question 7
To create a custom exception, you should inherit from the built-in _____ class.
✓
Correct!
Custom exceptions should inherit from Exception (or its subclasses), not BaseException. This follows Python’s exception hierarchy conventions.
✗
Incorrect
Custom exceptions should inherit from Exception (or its subclasses), not BaseException. This follows Python’s exception hierarchy conventions.
It’s the most common base class for user-defined exceptions.
Question 8
Why is it recommended to catch specific exceptions rather than using a broad
except Exception?✓
Correct!
Catching specific exceptions lets you handle known errors appropriately while allowing unexpected errors to surface. Broad catches can silently swallow bugs, making them extremely hard to diagnose. Python does not auto-log exceptions based on specificity.
✗
Incorrect
Catching specific exceptions lets you handle known errors appropriately while allowing unexpected errors to surface. Broad catches can silently swallow bugs, making them extremely hard to diagnose. Python does not auto-log exceptions based on specificity.
Think about what happens when you catch errors you don’t know how to handle.
Question 9
Complete the context manager pattern for automatic file cleanup:
Fill in the missing keyword
_____ open('data.txt', 'r') as f:
content = f.read()
# File automatically closed here✓
Correct!
The
with statement creates a context manager that handles setup (opening) and cleanup (closing) automatically, even if exceptions occur.✗
Incorrect
The
with statement creates a context manager that handles setup (opening) and cleanup (closing) automatically, even if exceptions occur.Question 10
Context managers created with
@contextmanager must contain a yield statement.✓
Correct!
The
yield statement in a @contextmanager function separates setup (before yield) from cleanup (after yield in finally). It’s required for the decorator to work correctly.✗
Incorrect
The
yield statement in a @contextmanager function separates setup (before yield) from cleanup (after yield in finally). It’s required for the decorator to work correctly.Consider what separates the setup and teardown phases.
Question 11
When should you use
raise without arguments in an except block?✓
Correct!
Using
raise alone re-raises the current exception with its original traceback intact. Option C is the key trap — bare raise does the opposite of suppression; it propagates the exception further up. To suppress, you’d use pass or contextlib.suppress.✗
Incorrect
Using
raise alone re-raises the current exception with its original traceback intact. Option C is the key trap — bare raise does the opposite of suppression; it propagates the exception further up. To suppress, you’d use pass or contextlib.suppress.Think about preserving the original error information.
Question 12
Which scenarios are appropriate for creating custom exceptions?
✓
Correct!
Create custom exceptions for domain-specific or application-specific errors. FileNotFoundError and ZeroDivisionError are already built-in exceptions.
✗
Incorrect
Create custom exceptions for domain-specific or application-specific errors. FileNotFoundError and ZeroDivisionError are already built-in exceptions.
Think about errors specific to your application vs. general Python errors.
Question 13
What is the output of this code?
try:
result = 10 / 0
except ZeroDivisionError:
print("A")
else:
print("B")
finally:
print("C")What will this code output?
✓
Correct!
ZeroDivisionError is caught, so except executes (prints ‘A’). Since an exception occurred, else is skipped. Finally always executes (prints ‘C’).
✗
Incorrect
ZeroDivisionError is caught, so except executes (prints ‘A’). Since an exception occurred, else is skipped. Finally always executes (prints ‘C’).
An exception occurred - which blocks run?
Question 14
What’s the difference between
raise ConfigError('msg') from e and raise ConfigError('msg') from None?✓
Correct!
Use
from e to chain exceptions — the original error is attached and visible in tracebacks. Use from None to suppress the chain when the original error is an implementation detail. Option D is the key trap: from e does not re-raise e, it creates a new exception with e as the cause.✗
Incorrect
Use
from e to chain exceptions — the original error is attached and visible in tracebacks. Use from None to suppress the chain when the original error is an implementation detail. Option D is the key trap: from e does not re-raise e, it creates a new exception with e as the cause.Think about whether you want to show or hide the underlying error.
Question 15
Assertions are suitable for validating user input or handling expected errors.
✓
Correct!
Assertions are for internal checks and programmer errors (bugs). Use exceptions for expected errors like invalid user input. Assertions can be disabled with
python -O, making them unreliable for critical validation.✗
Incorrect
Assertions are for internal checks and programmer errors (bugs). Use exceptions for expected errors like invalid user input. Assertions can be disabled with
python -O, making them unreliable for critical validation.Can assertions be disabled in production?
Question 16
When writing libraries or functions, you should _____ exceptions to signal problems. When calling that code, you should use try/except to _____ those exceptions.
✓
Correct!
Functions should raise exceptions when they detect invalid states (fail fast). Application code should catch those exceptions and decide how to handle them based on context.
✗
Incorrect
Functions should raise exceptions when they detect invalid states (fail fast). Application code should catch those exceptions and decide how to handle them based on context.
Think about the separation of concerns - detecting vs. handling errors.
Question 17
What is the mental model for when to create a custom context manager?
What is the mental model for when to create a custom context manager?
Decision trigger: “If I do X, must I always undo/cleanup Y — no matter what?”
If yes, create a context manager.
Structure: SETUP → USE → CLEANUP (guaranteed)
The core pattern is pairing setup with teardown operations that must always run together — even if an exception occurs.
Common scenarios:
- Temporary state changes (then restore)
- Resource acquisition/release (files, connections, locks)
- Transaction-like operations (commit/rollback)
- Timing/monitoring (start/end)
- Testing utilities (setup/cleanup)
Did you get it right?
✓
Correct!
✗
Incorrect
Question 18
Which approach is better for handling file operations and why?
✓
Correct!
Context managers (
with open(...)) automatically handle cleanup even if exceptions occur. Option C is the key trap: Python’s garbage collector may eventually close files, but it is non-deterministic and not guaranteed to run before the exception propagates — you cannot rely on it for resource safety.✗
Incorrect
Context managers (
with open(...)) automatically handle cleanup even if exceptions occur. Option C is the key trap: Python’s garbage collector may eventually close files, but it is non-deterministic and not guaranteed to run before the exception propagates — you cannot rely on it for resource safety.Think about automatic vs. manual resource management.
Question 19
Complete the custom exception class:
Fill in the missing class name
class ValidationError(_____):
def __init__(self, field, message):
self.field = field
super().__init__(f"{field}: {message}")✓
Correct!
Custom exceptions should inherit from
Exception (or its subclasses). This follows Python’s exception hierarchy and allows proper exception handling.✗
Incorrect
Custom exceptions should inherit from
Exception (or its subclasses). This follows Python’s exception hierarchy and allows proper exception handling.Question 20
When should you re-raise an exception after catching it?
✓
Correct!
Re-raise when you need to log/cleanup but can’t fully handle the error, or when you need to inspect but not handle certain error types. To suppress errors, use pass (carefully). To convert exceptions, use
raise NewException from e.✗
Incorrect
Re-raise when you need to log/cleanup but can’t fully handle the error, or when you need to inspect but not handle certain error types. To suppress errors, use pass (carefully). To convert exceptions, use
raise NewException from e.Re-raising means the error still propagates up the call stack.
Question 21
What does the
__exit__ method return value control in a custom context manager?✓
Correct!
__exit__ returns False to propagate exceptions (default) or True to suppress them. Option A is the classic trap: the as variable gets the return value of __enter__, not __exit__. Option C is wrong — the with block body always runs before __exit__ is called.✗
Incorrect
__exit__ returns False to propagate exceptions (default) or True to suppress them. Option A is the classic trap: the as variable gets the return value of __enter__, not __exit__. Option C is wrong — the with block body always runs before __exit__ is called.Think about what happens to exceptions that occur inside the with block.
Question 22
What happens when this code runs?
try:
value = int('abc')
except ValueError:
print('Error')
except TypeError:
print('Type Error')
else:
print('Success')What will this code output?
✓
Correct!
int('abc') raises ValueError (invalid literal), which is caught by the first except block. Once an exception is caught, else is skipped and no other except blocks execute.✗
Incorrect
int('abc') raises ValueError (invalid literal), which is caught by the first except block. Once an exception is caught, else is skipped and no other except blocks execute.What exception does int(‘abc’) raise?
Question 23
You should use
except: (bare except) instead of except Exception: for better error handling.✓
Correct!
Bare
except: catches everything including SystemExit and KeyboardInterrupt, which should usually propagate. Use except Exception: to avoid catching system exceptions, though catching specific exceptions is even better.✗
Incorrect
Bare
except: catches everything including SystemExit and KeyboardInterrupt, which should usually propagate. Use except Exception: to avoid catching system exceptions, though catching specific exceptions is even better.What system-level exceptions should you avoid catching?
Question 24
What is the guideline for deciding where to raise vs. where to catch exceptions?
What is the guideline for deciding where to raise vs. where to catch exceptions?
Raise where errors occur, catch where you can handle them
Functions/libraries should detect invalid states and raise exceptions — they shouldn’t decide how to handle the error.
Application code that calls functions should catch and handle exceptions based on the context and business requirements.
Did you get it right?
✓
Correct!
✗
Incorrect
Question 25
Which context manager from contextlib would you use to safely delete a file that might not exist?
✓
Correct!
suppress(FileNotFoundError) allows you to ignore specific exceptions cleanly. Option C (ExitStack) is the likely trap — it manages multiple context managers dynamically, but does not suppress exceptions. Option D (closing) calls .close() on exit, useful for objects without native context manager support.✗
Incorrect
suppress(FileNotFoundError) allows you to ignore specific exceptions cleanly. Option C (ExitStack) is the likely trap — it manages multiple context managers dynamically, but does not suppress exceptions. Option D (closing) calls .close() on exit, useful for objects without native context manager support.You want to suppress a specific exception type.
Question 26
Which statements about the exception hierarchy are correct?
✓
Correct!
User exceptions should inherit from Exception, not BaseException. NameError and AttributeError do not inherit from LookupError — LookupError only covers sequence/mapping lookups (IndexError, KeyError). NameError and AttributeError are direct subclasses of Exception.
✗
Incorrect
User exceptions should inherit from Exception, not BaseException. NameError and AttributeError do not inherit from LookupError — LookupError only covers sequence/mapping lookups (IndexError, KeyError). NameError and AttributeError are direct subclasses of Exception.
BaseException is for system exceptions. Check the hierarchy tree in the content.
Question 27
To log an exception with its full traceback automatically, use
logging._____(message) inside an except block.✓
Correct!
logging.exception() logs at ERROR level and automatically appends the current exception’s traceback — no extra formatting needed. logging.error() logs at the same level but does not include the traceback, so you lose the stack frames that show exactly where the error originated. Inside an except block, logging.exception() is almost always the right choice.✗
Incorrect
logging.exception() logs at ERROR level and automatically appends the current exception’s traceback — no extra formatting needed. logging.error() logs at the same level but does not include the traceback, so you lose the stack frames that show exactly where the error originated. Inside an except block, logging.exception() is almost always the right choice.The method name matches what you’re handling.
Question 28
When should you use
except (ValueError, TypeError): (tuple syntax) instead of two separate except blocks?✓
Correct!
Use tuple syntax when both exceptions warrant exactly the same response — it avoids duplicating the handler body. Use separate blocks when each error needs distinct recovery logic. Option C is the key trap:
as e in tuple syntax captures whichever exception actually occurred — not both simultaneously. You can never access two exceptions at once in a single handler. Inheritance relationships don’t determine which syntax to use.✗
Incorrect
Use tuple syntax when both exceptions warrant exactly the same response — it avoids duplicating the handler body. Use separate blocks when each error needs distinct recovery logic. Option C is the key trap:
as e in tuple syntax captures whichever exception actually occurred — not both simultaneously. You can never access two exceptions at once in a single handler. Inheritance relationships don’t determine which syntax to use.Think about what goes inside each handler body.
Question 29
What does this code print?
try:
result = 10 / 0
except ZeroDivisionError as e:
message = str(e)
print(message)What will this code output?
✓
Correct!
str(exception) returns just the exception’s message string — the human-readable description, not the class name. To get only the class name, use type(e).__name__. To get the full ClassName: message format you see in tracebacks, you’d need f"{type(e).__name__}: {e}". Option C is the likely trap: that’s the traceback format, not what str() returns.✗
Incorrect
str(exception) returns just the exception’s message string — the human-readable description, not the class name. To get only the class name, use type(e).__name__. To get the full ClassName: message format you see in tracebacks, you’d need f"{type(e).__name__}: {e}". Option C is the likely trap: that’s the traceback format, not what str() returns.What does str() return for an exception object?
Question 30
Python requires nested
with statements to manage multiple context managers simultaneously.✓
Correct!
A single
with statement can manage multiple context managers separated by commas: with open('in.txt') as f, open('out.txt', 'w') as g:. Context managers are entered left-to-right and exited right-to-left — exactly equivalent to nested with statements, but in one line. This pattern is especially useful for paired file operations.✗
Incorrect
A single
with statement can manage multiple context managers separated by commas: with open('in.txt') as f, open('out.txt', 'w') as g:. Context managers are entered left-to-right and exited right-to-left — exactly equivalent to nested with statements, but in one line. This pattern is especially useful for paired file operations.Think about how you would open two files at once.
Question 31
In a class-based context manager,
__exit__ is called with (None, None, None) for its three parameters. What does this indicate?✓
Correct!
Python always calls
__exit__(exc_type, exc_val, exc_tb). When all three are None, the with block completed normally with no exception. This is the signal cleanup code uses to decide commit vs. rollback: if exc_type is None: commit(). Option C is the key trap — return or break inside a with block still triggers __exit__ with (None, None, None), not with special sentinel values. The parameters only carry non-None values when an exception propagated out of the block.✗
Incorrect
Python always calls
__exit__(exc_type, exc_val, exc_tb). When all three are None, the with block completed normally with no exception. This is the signal cleanup code uses to decide commit vs. rollback: if exc_type is None: commit(). Option C is the key trap — return or break inside a with block still triggers __exit__ with (None, None, None), not with special sentinel values. The parameters only carry non-None values when an exception propagated out of the block.What do the three parameters collectively represent?
Question 32
What does this code print?
class AppError(Exception):
pass
class DatabaseError(AppError):
pass
try:
raise DatabaseError("connection failed")
except AppError:
print("caught AppError")
except DatabaseError:
print("caught DatabaseError")What will this code output?
✓
Correct!
Python evaluates except clauses top-to-bottom and stops at the first match. Since
DatabaseError inherits from AppError, the raised exception matches the first clause and the second is never reached — it is unreachable dead code. Python does not warn you about this. This is exactly why you should order except blocks from most specific to most general: if except DatabaseError appeared first, it would correctly catch DatabaseError while letting except AppError catch other subclasses.✗
Incorrect
Python evaluates except clauses top-to-bottom and stops at the first match. Since
DatabaseError inherits from AppError, the raised exception matches the first clause and the second is never reached — it is unreachable dead code. Python does not warn you about this. This is exactly why you should order except blocks from most specific to most general: if except DatabaseError appeared first, it would correctly catch DatabaseError while letting except AppError catch other subclasses.Which except clause does Python reach first, and does DatabaseError satisfy it?
Question 33
What does this code print?
def load_config(path):
try:
with open(path) as f:
return f.read()
except Exception:
pass
config = load_config("missing.json")
print(config is None)What will this code output?
✓
Correct!
When
open("missing.json") raises FileNotFoundError, the except block catches it — but pass does nothing, and the function exits without a return statement. Python implicitly returns None. The caller then unknowingly uses None as if it were a config string, likely causing an AttributeError or TypeError deep in unrelated code — making the original bug nearly impossible to trace. This is the silent failure anti-pattern: the error is swallowed, and debugging becomes a nightmare.✗
Incorrect
When
open("missing.json") raises FileNotFoundError, the except block catches it — but pass does nothing, and the function exits without a return statement. Python implicitly returns None. The caller then unknowingly uses None as if it were a config string, likely causing an AttributeError or TypeError deep in unrelated code — making the original bug nearly impossible to trace. This is the silent failure anti-pattern: the error is swallowed, and debugging becomes a nightmare.What does a Python function return when execution reaches the end with no return statement?
Question 34
A function reads a 10GB file, runs a 30-second analysis, then writes results to an output path provided by the caller. If the output path is invalid, when should you detect this?
✓
Correct!
The fail-fast principle: validate inputs early to surface errors before spending resources. Detecting the bad path after 30 seconds of processing wastes compute and the user’s time — and they have to wait again after fixing it. Option D still catches the error but too late. Option C (finally) runs after the work is done, not before. Option A is exactly the anti-pattern this principle prevents: the “overhead” of early validation is microseconds vs. 30 seconds of wasted work.
✗
Incorrect
The fail-fast principle: validate inputs early to surface errors before spending resources. Detecting the bad path after 30 seconds of processing wastes compute and the user’s time — and they have to wait again after fixing it. Option D still catches the error but too late. Option C (finally) runs after the work is done, not before. Option A is exactly the anti-pattern this principle prevents: the “overhead” of early validation is microseconds vs. 30 seconds of wasted work.
When should you surface an error relative to expensive work?
Quiz Results
Score
0/0
Accuracy
0%
Right
0
Wrong
Skipped
0
Last updated on