Home / Computer Science / Class XII / Exception Handling in Python
Exception Handling in Python — CUET Computer Science hero
Class XII 💻 Computer Science Ch 1 of 20

Exception Handling in Python

CUET unit: Exception Handling in Python

📌 Snapshot

  • Learn how Python survives runtime errors with try, except, else and finally, and which block runs when.
  • Syntax errors, exceptions and logical errors compared, plus all twelve built in exceptions with their triggers.
  • How raise and assert create exceptions, and how Python hunts for a handler through the chain of function calls.
  • Output tracing tables for every combination of error and no error, the part of this chapter CUET tests most.

📖 Detailed Notes

Written and reviewed by Rohit Singh, Computer Science & Commerce faculty at UniDrill (MCA, Osmania University · 6 years teaching). Based on NCERT Computer Science Class XII, Chapter 1.

What happens when the user types "ten" instead of 10?

A shop billing program asks, "How many items?" and the customer types ten. The call int("ten") cannot convert the text, Python stops the program mid-bill and prints a red wall of text. Everything the cashier had entered so far is gone.

Exception handling is the cure. It lets your program notice the problem, say "Please type digits", ask again and carry on, instead of crashing. This chapter is about three questions: what kinds of errors exist, how Python reports them, and how you catch them. The last one, which block of a try statement runs when, is the single most tested skill in the chapter.

Three kinds of errors

Not every mistake in a program is an exception. Python meets errors at different moments, and the moment decides what you can do about it.

Kind Found when What Python does Example
Syntax error (parsing error) Before the program runs, while reading the code Refuses to run any of it, names the error and gives a short description print "Hello" or an if line with no colon
Exception (runtime error) While the program runs, on a line that is correctly written Stops at that line, prints the error name and reason, unless your code handles it print(50 / 0)
Logical error Never reported Runs happily and gives the wrong answer Averaging with a + b / 2 instead of (a + b) / 2

Why the difference matters. A syntax error breaks the rules of the language, so Python cannot even understand the program and will not start it. An exception is different: the statement is fine as written, but something about the data at that moment makes it impossible, such as dividing by zero or opening a file that does not exist. Only exceptions can be handled by your own code. A logical error produces no message at all, which makes it the hardest to find.

An exception is a Python object that represents an error. Once it is raised, normal execution is interrupted. SyntaxError is itself an exception object too, but it is the only one that appears for a program with wrong syntax. Every other exception can occur only when the syntax is correct.

The twelve built in exceptions

Python's standard library already defines an exception for every common mistake. When one occurs, the interpreter shows its name and the reason. You can also define your own (user defined) exceptions, but the exam concentrates on these twelve.

Exception Raised when Typical trigger
SyntaxError The rules of the language are broken print "Hi"
ValueError A function gets the right type of argument but an unsuitable value int("abc")
IOError An input or output operation fails, such as a missing file open("nofile.txt")
KeyboardInterrupt The user interrupts the running program, for example by hitting the Delete or Esc key Interrupting a long loop
ImportError The module to be imported is not found import nosuchmodule
EOFError input() reaches the end of the input without reading any data input() when no more input is available
ZeroDivisionError The denominator of a division is zero print(50 / 0)
IndexError An index or subscript is out of range [10, 20, 30][5]
NameError A local or global name is not defined print(var + 40) with no var
IndentationError The indentation of the code is wrong The body of an if not indented
TypeError An operator or function gets a value of the wrong type 10 + '5'
OverflowError A calculation result is too large for the numeric type math.exp(1000)

Pause and predict: what happens with int("3.5"), and what happens with int(3.5)?

Check your answer: int("3.5") raises ValueError, because the argument is a string (a fine type for int) but the text is not a whole number. int(3.5) raises nothing and gives 3, because a float is converted by dropping the fraction. ValueError means "right type, wrong value", while TypeError means "wrong type altogether".

Beyond the textbook. For the exam: IOError is raised when a file operation fails, for example opening a file that does not exist. In reality: in Python 3, IOError is just another name for OSError, and a missing file actually raises FileNotFoundError, which is a more specific kind of OSError. Code written as except IOError: still catches it, so the exam answer and the real behaviour agree.

raise: forcing an exception

Python raises exceptions on its own when it detects an error. You can also raise one yourself when your program finds a situation that should not continue. The syntax is raise exception-name[(optional argument)], where the optional argument is a message string.

Raising an exception interrupts the normal flow, and no further statement in the current block executes. Study this program:

Code
numbers = [40, 50, 60, 70]
length = 10
if length > len(numbers):
    raise IndexError
    print("NO EXECUTION")
else:
    print(length)

Since 10 is greater than 4, the if branch runs and raise IndexError fires. The print("NO EXECUTION") right after it is never reached. The program ends with a traceback, which lists the calls that led to the error, and its last line names the exception.

Output
Traceback (most recent call last):
IndexError

assert: a guard at the start of a function

The assert statement tests an expression. If the expression is True nothing happens. If it is False, Python raises AssertionError with your message. The syntax is assert Expression[, arguments]. It is used at the beginning of a function, or right after a call, to check that the input is valid.

Code
import math
def root(n):
    assert n >= 0, "OOPS... Negative Number"
    return math.sqrt(n)
print(root(16))
print(root(-4))
Output
4.0
AssertionError: OOPS... Negative Number

The first call passes the test. The second fails it, so return is never reached and the program stops (the traceback lines in between are left out above).

Feature raise assert
Raises when Always, when the statement runs Only if the tested expression is False
Exception it raises Any exception you name AssertionError only
Typical use Signal a problem you detected Check that inputs are valid
Optional extra A message in brackets A message after a comma

Beyond the textbook. For the exam: assert raises AssertionError when the expression is False. In reality: Python can be started in an optimised mode that removes every assert statement before the program runs. So real programs never rely on assert to check user input. They use an if with raise instead, and keep assert for debugging checks.

Why handle exceptions at all?

Without a handler, the first exception ends the whole program. Handling gives you four benefits. Python sorts errors into distinct types, so each can get its own response. The error response code is separated from the main logic, so the main logic stays readable. The interpreter reports the exact position of the error. Both built in and user defined exceptions can be handled.

How Python looks for a handler

When an error occurs, Python builds an exception object holding the type of error, the file name and the position. Handing this object to the runtime system is called throwing the exception. The runtime then looks for a piece of code that can deal with it, called an exception handler, first in the current function. If there is none, it searches the functions that called this one, in reverse order. This list of waiting calls is the call stack, and passing the problem outward is forwarding the exception. Running a suitable handler is catching. If every function in the stack has been searched without luck, the program terminates and prints the traceback.

Step Term What happens
1 Error occurs An exception object is created
2 Throwing The object is handed to the runtime system
3 Search Handler looked for in the current function
4 Forwarding If not found, callers are searched in reverse order
5 Catching A matching handler runs
6 Termination No handler anywhere: program stops with a traceback

Worked example: tracing the search. Where is the exception of this program caught?

Code
def divide(a, b):
    return a / b
def calc():
    return divide(10, 0)
try:
    calc()
except ZeroDivisionError:
    print("caught in main")
Step Where Python looks Handler there? Result
1 divide, where 10 / 0 fails No Forward to the caller
2 calc, which called divide No Forward to the caller
3 Main program, inside try Yes, except ZeroDivisionError Caught, prints caught in main

Pause and predict: in this program, what changes if the handler is written as except ValueError: instead?

Check your answer: ValueError does not match a ZeroDivisionError, so no handler exists anywhere in the chain. Python prints the traceback and terminates, and caught in main is never printed. A handler catches only the exception type it names.

try and except: catching an exception

Place the suspicious statements in a try block. Every try is followed by one or more except blocks with the handler code. When a statement in try raises an exception, the rest of the try block is skipped and control jumps to the matching except. After that handler finishes, the program continues with the first statement after the whole construct.

Code
try:
    numerator = 50
    denom = int(input("Enter the denominator: "))
    quotient = numerator / denom
    print("Division performed successfully")
except ZeroDivisionError:
    print("Denominator as ZERO is not allowed")
except ValueError:
    print("Only INTEGERS should be entered")
print("OUTSIDE try..except block")
User types Where it breaks Output
5 Nowhere Division performed successfully, then OUTSIDE try..except block
0 numerator / denom raises ZeroDivisionError, so the success message is skipped Denominator as ZERO is not allowed, then OUTSIDE try..except block
abc int(...) raises ValueError before the division Only INTEGERS should be entered, then OUTSIDE try..except block

Four rules follow from this table. Only the first matching except runs, and the rest are skipped. A statement placed before the try is not protected, because the try must surround the risky code. A bare except: with no exception name is a catch-all, and it must be the last handler. Python reads the handlers from top to bottom, so a catch-all placed first would swallow every exception and hide the specific ones below it.

Beyond the textbook. For the exam: a bare except must be written last. In reality: Python enforces this itself and reports a SyntaxError if a bare except: is not last. A bare except also catches KeyboardInterrupt, so a user cannot stop the program with the interrupt key (Ctrl+C on most systems). Careful programmers name the exceptions they expect.

else and finally: the full construct

Two optional clauses complete the statement. The else block comes after all the except blocks and runs only if the try block raised no exception. The finally block comes last and runs always: after success, after a handled exception, and even when the exception is not handled. In the unhandled case the exception is raised again after the finally block finishes. The order is fixed: try, then except blocks, then else, then finally.

Code
try:
    x = int(input("X: "))
    q = 10 / x
except ZeroDivisionError:
    print("ZE")
else:
    print("Q =", q)
finally:
    print("FIN")
User types try block except else finally Output
5 Completes Skipped Runs Runs Q = 2.0 then FIN
0 Stops at 10 / x ZeroDivisionError handler runs Skipped Runs ZE then FIN
abc Stops at int(...) No match for ValueError Skipped Runs, then the error is raised again FIN, then a ValueError traceback

Why use else at all? You could print the quotient at the end of try. The difference is protection: any exception raised inside try is looked after by the handlers, while code in else is outside that protection. Keeping only the risky line in try and the follow up work in else means a bug in the follow up is never mistaken for the error you were expecting.

Why finally exists. Some actions must happen whatever goes wrong. Closing a file is the standard case, since a file left open can lose data. Putting close() in finally guarantees it runs.

Worked example: predict the output.

Code
def test(a, b):
    try:
        r = a / b
        print("A")
    except ZeroDivisionError:
        print("B")
    else:
        print("C")
    finally:
        print("D")
    print("E")
test(6, 3)
test(6, 0)
test("6", 3)
Call What happens Printed
test(6, 3) Division works, so try, else and finally run, then the line after A, C, D, E
test(6, 0) ZeroDivisionError, so handler and finally run, then the line after B, D, E
test("6", 3) Dividing text by a number raises TypeError, which no handler matches. finally runs, then the program stops D, then a TypeError traceback. E never prints

The common wrong step is to think finally cancels the error. It does not: finally runs first, but an unhandled exception still ends the program afterwards.

Pause and predict: can finally appear without any except block?

Check your answer: Yes. A try may be followed by finally alone. The code in finally still runs, and any exception is raised again afterwards, since nothing has handled it.

Exam traps

Trap Why it tempts Truth
finally runs only when an error occurs Cleanup sounds like error handling finally always runs
else runs when an exception occurs In English, "else" suggests "otherwise" else runs only when the try block raised no exception
finally handles the exception It sits beside except Only except catches. After finally, an unhandled exception is raised again
Statements after raise still run The lines are right there in the block Nothing after raise in that block executes
Several matching except blocks all run More handlers feels like more coverage Only the first matching one runs
assert raises ValueError A false value seems like a bad value assert raises AssertionError
A line before try is protected It is in the same function Only the code inside try is protected
SyntaxError is not an exception Syntax errors feel different from runtime errors SyntaxError is an exception, but it is the only one that arises when the syntax is wrong

60-second revision

Idea Remember
Syntax error Found before running, program will not start
Exception Raised at run time on correct syntax
Logical error No message, wrong answer
raise raise ExceptionName("message") forces an exception; nothing after it runs
assert assert condition, "message" raises AssertionError if the condition is False
Handler search Current function, then callers in reverse (forwarding), else program ends
try Holds the risky statements
except Runs for a matching exception; bare except: goes last
else Runs only if no exception occurred
finally Always runs; used for cleanup such as closing files
Order try, except, else, finally

Where this chapter connects

Files fail in all the ways this chapter describes, so File Handling in Python uses finally, with and EOFError constantly. The call stack that Python searches for a handler is the same last in, first out idea you meet in Stack.

🎯 Practice MCQs

First 3 questions free · create a free account to unlock the rest — answers & explanations included, no payment needed

Q1. Which of the following statements about syntax errors in Python is correct?

▸ Show answer & explanation

Answer: B

The interpreter finds syntax errors while reading the code, before running it, and will not execute the program until they are fixed. Option A describes an IOError situation, option C describes runtime exceptions, and option D is wrong because shell mode also reports syntax errors immediately.

Q2. Consider: (1) numbers = [40, 50, 60, 70] (2) length = 10 (3) an if block that runs when length > len(numbers) and contains raise IndexError followed by print("NO EXECUTION") (4) an else block that prints length. What is the result?

▸ Show answer & explanation

Answer: D

Since 10 is greater than 4, the if block runs and raise IndexError executes. After a raise, no further statement in that block runs, so the print after it is skipped. Option C is wrong for that reason, and options A and B ignore the raised exception.

Q3. Which statement correctly describes assert in Python?

▸ Show answer & explanation

Answer: D

assert raises AssertionError, not ValueError, when the tested expression is False. Option A describes try with except. Option D is wrong because assert is typically used at the beginning of a function or after a call to check that input is valid.

🔒 12 more practice MCQs

Create a free account to unlock every MCQ in this chapter — answers and explanations included. No payment needed.

Already registered? Just log in and they'll all appear here.

📊 Previous-Year Questions

Practise with real CUET Computer Science previous-year papers — every question solved, with the correct answer and a step-by-step explanation.

View solved CUET PYQ papers →

Ready to drill Computer Science?

Unlock all MCQs, chapter tests, mocks & PYQs for ₹199/year.

Get UniDrill Pro