🎓 Velnov

🐍 Python · Topic 11 of 20

Error Handling — Python Questions with Answers

Start with the study notes on Error Handling (definitions, examples and a quick revision), then work through 30 practice questions, each with the correct answer and a clear explanation of why it is right. When you are ready, take this topic as an interactive quiz to test yourself.

9 easy · 15 medium · 6 hard · Part of Python: Master Python from basics to advanced - 20 topics.

Topic overview

Error Handling – try, except, else and finally

1. Exceptions vs syntax errors

An uncaught exception stops the program and prints a traceback. Read it from the bottom: the last line names the exception and its message.

2. Common exceptions

3. try and except

Put the risky code in try. If it raises an exception, the matching except block runs instead of the program crashing. Use as e to get the message.

try:
    n = int("abc")
except ValueError as e:
    print("Bad value:", e)
print("program continues")
OutputBad value: invalid literal for int() with base 10: 'abc'
program continues

Trace what happens

try:
    print("A")
    x = 1 / 0
    print("B")          # skipped
except ZeroDivisionError:
    print("C")
print("D")
OutputA
C
D

4. Handling several exceptions

for text in ["5", "zero", "0"]:
    try:
        print(10 / int(text))
    except ValueError:
        print("not a number")
    except ZeroDivisionError:
        print("can't divide by zero")
Output2.0
not a number
can't divide by zero

5. else and finally

def convert(text):
    try:
        n = int(text)
    except ValueError:
        print("bad input")
    else:
        print("got", n)
    finally:
        print("done")

convert("7")
convert("x")
Outputgot 7
done
bad input
done

6. Raising your own exceptions

raise triggers an exception on purpose. For your own error types, create a class that inherits from Exception.

class InsufficientFunds(Exception):
    pass

def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFunds(f"short by {amount - balance}")
    return balance - amount

try:
    withdraw(100, 150)
except InsufficientFunds as e:
    print("Error:", e)
OutputError: short by 50

Remember: Raising is better than returning -1: an exception can't be silently ignored. A bare raise inside except re-raises the same error.

7. Asking until the input is valid

while True:
    try:
        n = int(input("Number: "))
        break
    except ValueError:
        print("Not a number - try again")

8. Good habits

d = {"a": 1}
try:
    value = d["b"]
except KeyError:
    value = 0
print(value)
Output0

9. Common misconceptions

MisconceptionCorrect understanding
try/except can catch a missing colon.Syntax errors are found before running and can't be caught.
A bare except: is the safest choice.It hides real bugs; catch the specific exceptions you expect.
finally runs only if there was an error.finally always runs.
int("abc") is a TypeError.It is a ValueError: right type, bad value.
else in try runs when there is an error.else runs only when no exception occurred.

10. Quick revision

Exception
An error that happens while the program runs.
Traceback
The error report; read the last line first.
try / except
Run risky code / handle its error.
as e
Gives access to the exception and its message.
else
Runs when no exception happened.
finally
Always runs; used for cleanup.
raise
Triggers an exception on purpose.
EAFP
Try first, handle the error if it happens.

11. Test your understanding

  1. Which exception does 10 / 0 raise?

    Show answer

    ZeroDivisionError.

  2. Which exception does int("abc") raise?

    Show answer

    ValueError.

  3. How do you get the error message inside except?

    Show answer

    except ValueError as e: then print(e).

  4. How do you catch two exception types with one handler?

    Show answer

    except (ValueError, TypeError):

  5. When does the finally block run?

    Show answer

    Always.

  6. When does the else block of a try run?

    Show answer

    Only when the try block raised no exception.

  7. How do you create your own exception type?

    Show answer

    class MyError(Exception): pass

  8. Why is a bare except: bad practice?

    Show answer

    It hides real bugs and even catches Ctrl+C.

Key takeaway: Wrap only the risky line in try, catch the specific exceptions you expect, use finally for cleanup, and raise clear errors of your own.

Notes written by Velnov. Every code example with an output was run in Python 3 to check that the output shown is exactly what Python prints.

Key concepts in this topic

Runtime errorsSyntaxError vs exceptionstry/exceptZeroDivisionErrorValueErrorTypeErrorIndexErrorKeyErrorNameErrorTyposTracebackDebuggingControl flowException objectsas keywordMultiple exceptException matchingException tuplestry/elseMinimal try blocksfinallyCleanupraiseValidation

Jump to: Easy · Medium · Hard

Easy questions (9)

Q1. easy

What is an exception in Python?

  1. A A syntax mistake caught before running
  2. B An error that occurs WHILE the program runs, which can be caught and handled
  3. C A warning message
  4. D A special comment

Answer: B — An error that occurs WHILE the program runs, which can be caught and handled

Exceptions are runtime errors - division by zero, missing file, bad conversion. Unlike syntax errors (caught before the program starts), exceptions happen mid-run and CAN be caught with try/except.

Runtime errorsSyntaxError vs exceptions

Q2. easy

Which is the correct basic structure for handling an error?

try:
    n = int(input("Number: "))
except ValueError:
    print("That's not a number")
  1. A try:\n risky()\nexcept:\n handle()
  2. B attempt:\n risky()\nrescue:\n handle()
  3. C try risky() catch handle()
  4. D if error: handle()

Answer: A — try:\n risky()\nexcept:\n handle()

Python uses try/except: the risky code goes in try; if it raises an exception, the except block runs instead of crashing.

try/except

Q3. easy

What exception does 10 / 0 raise?

try:
    print(10 / 0)
except ZeroDivisionError:
    print("Can't divide by zero!")
  1. A ValueError
  2. B ZeroDivisionError
  3. C MathError
  4. D TypeError

Answer: B — ZeroDivisionError

Dividing by zero raises ZeroDivisionError. Its message: 'division by zero'.

ZeroDivisionError

Q4. easy

What exception does int("abc") raise?

try:
    n = int("abc")
except ValueError as e:
    print("Bad value:", e)
  1. A TypeError
  2. B NameError
  3. C ValueError
  4. D ConversionError

Answer: C — ValueError

The TYPE is right (a string) but the VALUE can't be converted - that's ValueError. TypeError would be for a wrong type entirely, like int([1,2]).

ValueErrorTypeError

Q6. easy

Using a variable that was never defined raises:

  1. A NameError
  2. B ValueError
  3. C KeyError
  4. D UndefinedError

Answer: A — NameError

NameError: name 'x' is not defined - Python doesn't know that name. Often caused by typos in variable names.

NameErrorTypos

Q7. easy

What happens to a program when an exception is NOT caught?

  1. A It continues from the next line
  2. B It stops and prints a traceback showing where the error happened
  3. C It restarts
  4. D Nothing visible

Answer: B — It stops and prints a traceback showing where the error happened

An unhandled exception crashes the program and prints a traceback - the chain of calls that led to the error, ending with the exception type and message. Learning to READ tracebacks is a superpower.

  • Read tracebacks bottom-up: the last line names the error; lines above show where.

TracebackDebugging

Q14. easy

Which statement deliberately TRIGGERS an exception?

def set_age(age):
    if age < 0:
        raise ValueError("age cannot be negative")
    return age
  1. A raise
  2. B throw
  3. C error
  4. D panic

Answer: A — raise

raise fires an exception on purpose: raise ValueError("age cannot be negative"). (throw is Java/JavaScript.)

raiseValidation

Q26. easy

"hello" + 5 raises which exception?

  1. A ValueError
  2. B TypeError
  3. C NameError
  4. D SyntaxError

Answer: B — TypeError

Mixing incompatible TYPES (str + int) is TypeError: can only concatenate str (not "int") to str. Compare: int("abc") is ValueError - right type, bad value.

TypeErrorValueError

Q29. easy

Which of these is a SYNTAX error rather than an exception?

  1. A if x > 5 (missing colon)
  2. B 10 / 0
  3. C int("abc")
  4. D nums[99]

Answer: A — if x > 5 (missing colon)

A missing colon breaks Python's grammar - detected BEFORE the program even starts, and try/except cannot catch it. The other three are runtime exceptions.

SyntaxErrorRuntime vs parse time

Medium questions (15)

Q5. medium

Match the exception: accessing nums[10] when nums has 3 items?

nums = [1, 2, 3]
# nums[10]        # IndexError: list index out of range
d = {"a": 1}
# d["z"]           # KeyError: 'z'
  1. A KeyError
  2. B IndexError
  3. C ValueError
  4. D RangeError

Answer: B — IndexError

Lists raise IndexError for out-of-range positions. KeyError is the dict equivalent (missing key). There is no RangeError in Python.

IndexErrorKeyError

Q8. medium

In a try/except, what runs when NO exception occurs?

try:
    print("works fine")
except ValueError:
    print("never printed here")
# output: works fine
  1. A Both try and except blocks
  2. B Only the try block - except is skipped entirely
  3. C Only the except block
  4. D Neither

Answer: B — Only the try block - except is skipped entirely

except is the emergency exit - it only runs when its exception actually happens. On a clean run, the try body completes and except is ignored.

Control flow

Q9. medium

How do you get the error MESSAGE inside except?

try:
    int("abc")
except ValueError as e:
    print("Problem:", e)
# Problem: invalid literal for int() with base 10: 'abc'
  1. A except ValueError as e: print(e)
  2. B except ValueError: print(error)
  3. C except ValueError(e): print(e)
  4. D print(except.message)

Answer: A — except ValueError as e: print(e)

'as e' binds the exception object to a name; printing it shows the message. e is only available inside that except block.

Exception objectsas keyword

Q10. medium

How do you handle TWO different exceptions DIFFERENTLY?

try:
    n = int(input())
    print(10 / n)
except ValueError:
    print("Not a number")
except ZeroDivisionError:
    print("Can't divide by zero")
  1. A Multiple except blocks, one per exception type
  2. B Two try blocks
  3. C except handles everything the same way always
  4. D Use if/else inside try

Answer: A — Multiple except blocks, one per exception type

Stack except blocks - Python runs the FIRST one matching the raised exception. Order specific-to-general.

Multiple exceptException matching

Q11. medium

How do you catch ValueError AND TypeError with the SAME handler?

try:
    risky()
except (ValueError, TypeError) as e:
    print("Bad input:", e)
  1. A except (ValueError, TypeError):
  2. B except ValueError and TypeError:
  3. C except ValueError, TypeError:
  4. D except [ValueError, TypeError]:

Answer: A — except (ValueError, TypeError):

A TUPLE of exception types shares one handler: except (ValueError, TypeError) as e. Option C was Python 2 syntax and is now an error.

Exception tuples

Q13. medium

When does the FINALLY block run?

try:
    risky()
except ValueError:
    print("handled")
finally:
    print("always runs")  # cleanup here
  1. A Only on success
  2. B Only on error
  3. C ALWAYS - success, exception, even a return
  4. D Only if except matched

Answer: C — ALWAYS - success, exception, even a return

finally is guaranteed cleanup - it runs no matter how the try block exits: normally, via an exception (caught or not), or via return/break. Perfect for closing files and connections.

finallyCleanup

Q15. medium

Why raise an exception in your OWN function instead of returning -1 or None on bad input?

def withdraw(balance, amount):
    if amount > balance:
        raise ValueError("insufficient funds")
    return balance - amount
  1. A Exceptions can't be ignored silently, carry a clear message, and stop bad data spreading
  2. B Exceptions are faster
  3. C return doesn't work for errors
  4. D No reason - error codes are better

Answer: A — Exceptions can't be ignored silently, carry a clear message, and stop bad data spreading

A returned -1 can be forgotten and treated as data; a raised exception demands attention and pinpoints the problem. 'Errors should never pass silently' - the Zen of Python.

raiseAPI design

Q17. medium

Trying to open a file that doesn't exist raises:

try:
    f = open("nofile.txt")
except FileNotFoundError:
    print("File not found - creating a new one")
  1. A FileNotFoundError
  2. B IOError only in Python 2
  3. C MissingFileError
  4. D KeyError

Answer: A — FileNotFoundError

open("nofile.txt") raises FileNotFoundError - one of the most commonly handled exceptions in real programs.

FileNotFoundErrorFiles

Q18. medium

What is the output? try: print("A") x = 1 / 0 print("B") except ZeroDivisionError: print("C") print("D")

  1. A A C D
  2. B A B C D
  3. C A C
  4. D C D

Answer: A — A C D

'A' prints, then 1/0 raises - the rest of try ('B') is SKIPPED, control jumps to except ('C'), and the program continues normally after ('D').

  • Key point: the try block stops at the line that raised.

Control flowTracing

Q19. medium

Which loop keeps asking until the user types a valid number?

while True:
    try:
        n = int(input("Number: "))
        break
    except ValueError:
        print("Not a number - try again")
  1. A while True:\n try:\n n = int(input()); break\n except ValueError:\n print("try again")
  2. B try until valid: n = int(input())
  3. C n = int(input()) repeat except
  4. D for i in valid: input()

Answer: A — while True:\n try:\n n = int(input()); break\n except ValueError:\n print("try again")

The standard robust-input pattern: loop forever, try the conversion, break on success, catch ValueError and re-ask on failure.

Input validationwhile True

Q23. medium

Inside except, what does a bare 'raise' (no arguments) do?

try:
    process()
except ValueError:
    print("logging the error...")
    raise    # pass it up unchanged
  1. A Re-raises the SAME exception it just caught
  2. B Raises a new generic Exception
  3. C Cancels the exception
  4. D SyntaxError

Answer: A — Re-raises the SAME exception it just caught

Bare raise re-throws the current exception - useful to log or clean up but still let the error propagate upward for someone else to handle.

Re-raisingLogging

Q24. medium

except Exception: catches...

  1. A Almost all normal errors - but NOT KeyboardInterrupt or SystemExit
  2. B Absolutely everything including Ctrl+C
  3. C Only built-in exceptions
  4. D Only one error per program

Answer: A — Almost all normal errors - but NOT KeyboardInterrupt or SystemExit

Nearly every error inherits from Exception. KeyboardInterrupt (Ctrl+C) and SystemExit inherit from BaseException instead - deliberately, so except Exception doesn't block a user trying to quit. That's why it's safer than a bare except.

Exception hierarchyBaseException

Q25. medium

What is the output? def f(): try: return "from try" finally: print("cleanup") print(f())

def f():
    try:
        return "from try"
    finally:
        print("cleanup")   # runs first!
print(f())
# cleanup
# from try
  1. A cleanup then from try
  2. B from try then cleanup
  3. C only from try
  4. D only cleanup

Answer: A — cleanup then from try

finally runs even on return - the return value is computed, finally executes ('cleanup'), THEN the function actually returns ('from try' is printed by the outer print).

finallyreturn interaction

Q27. medium

Where in a traceback do you find the actual error?

  1. A The FIRST line
  2. B The LAST line names the exception; the lines above show the path of calls to it
  3. C The middle
  4. D Tracebacks don't show errors

Answer: B — The LAST line names the exception; the lines above show the path of calls to it

Read from the bottom: last line = exception type + message; the 'File ..., line ...' entries above show where - the DEEPEST one is usually your bug. 'most recent call last' means the bottom entries are closest to the error.

TracebackDebugging

Q30. medium

Best practice: which code goes INSIDE the try block?

try:
    n = int(text)          # only the risky line
except ValueError:
    n = 0
result = n * 2              # safe code outside
  1. A As little as possible - only the line(s) that can actually fail
  2. B The whole program
  3. C Only print statements
  4. D Nothing - try can be empty

Answer: A — As little as possible - only the line(s) that can actually fail

Small try blocks make it obvious WHICH operation failed and avoid accidentally catching unrelated bugs. Wrap the risky line, handle the specific error, keep the rest outside (or in else).

Best practicestry/else

Hard questions (6)

Q12. hard

What does the ELSE clause do in try/except/else?

try:
    n = int(text)
except ValueError:
    print("bad input")
else:
    print("got number", n)   # only on success
  1. A Runs when an exception WAS raised
  2. B Runs only when the try block completed WITHOUT any exception
  3. C Always runs
  4. D Same as finally

Answer: B — Runs only when the try block completed WITHOUT any exception

else is the 'success path' - it runs after a clean try. Putting follow-up code there (rather than inside try) keeps the try block small, so you only catch errors from the truly risky line.

try/elseMinimal try blocks

Q16. hard

Why is a BARE except (catching everything) considered bad practice?

# BAD - hides all bugs:
try: process()
except: pass

# GOOD:
try: process()
except FileNotFoundError:
    print("file missing")
  1. A It's slower
  2. B It hides real bugs and even catches Ctrl+C - you can't tell WHAT went wrong
  3. C It's a syntax error in Python 3
  4. D It only catches ValueError

Answer: B — It hides real bugs and even catches Ctrl+C - you can't tell WHAT went wrong

except: swallows EVERYTHING - typos (NameError), logic bugs, even KeyboardInterrupt - making failures invisible. Catch the specific exceptions you expect; at worst use except Exception as e and log it.

Bare exceptBest practices

Q20. hard

What does assert x > 0, "x must be positive" do?

def average(nums):
    assert len(nums) > 0, "empty list!"
    return sum(nums) / len(nums)
  1. A Raises AssertionError with that message if the condition is False
  2. B Prints the message always
  3. C Converts x to positive
  4. D Nothing in any mode

Answer: A — Raises AssertionError with that message if the condition is False

assert is a development-time sanity check: if the condition fails, AssertionError is raised with your message. Note: assertions are STRIPPED when Python runs with -O, so never use them for real input validation.

assertAssertionError

Q21. hard

What is EAFP - the Pythonic error philosophy?

# EAFP (Pythonic):
try:
    value = d["key"]
except KeyError:
    value = default

# LBYL:
if "key" in d:
    value = d["key"]
  1. A 'Easier to Ask Forgiveness than Permission' - just try it and catch the exception, instead of checking first
  2. B 'Every Assertion Fails Predictably'
  3. C A testing framework
  4. D 'Except All, Fix Later'

Answer: A — 'Easier to Ask Forgiveness than Permission' - just try it and catch the exception, instead of checking first

EAFP: try the operation and handle failure - vs LBYL ('Look Before You Leap'): check conditions first. Python favors EAFP: it avoids race conditions and duplicate checks.

EAFP vs LBYLPython philosophy

Q22. hard

How do you define your OWN exception type?

class InsufficientFunds(Exception):
    pass

def withdraw(bal, amt):
    if amt > bal:
        raise InsufficientFunds(f"short by {amt - bal}")
  1. A class InsufficientFunds(Exception): pass
  2. B def InsufficientFunds(Exception):
  3. C exception InsufficientFunds:
  4. D new Exception("InsufficientFunds")

Answer: A — class InsufficientFunds(Exception): pass

Custom exceptions are classes inheriting from Exception - often just 'pass' bodies. They let callers catch YOUR specific error: except InsufficientFunds.

Custom exceptionsInheritance

Q28. hard

What is the output? try: try: 1 / 0 except ValueError: print("inner") except ZeroDivisionError: print("outer")

  1. A inner
  2. B outer
  3. C inner outer
  4. D Uncaught error

Answer: B — outer

The inner except only handles ValueError - it does NOT match ZeroDivisionError, so the exception keeps travelling outward until the OUTER handler matches: 'outer'. Unmatched exceptions bubble up.

Exception propagationNested try

Practice “Error Handling” as a quiz