ЁЯФм
ЁЯзм
ЁЯФн
ЁЯкР
ЁЯзк
тЖР Back to Dashboard
Font Size:

1. Introduction

Errors are an unavoidable part of programming. No matter how carefully a program is written, unexpected situations can occur at run time: the user may type a letter where a number is expected, a file may not exist, or the network may be down. In Python, these run-time anomalies are called exceptions. An exception is an event that disrupts the normal flow of the program's instructions. When an exception occurs, the Python interpreter stops executing the current code and reports the error by generating a traceback message.

Traditionally, programmers handled such situations by writing lots of if statements to check every possible error condition, which made code long, cluttered and hard to read. Exception handling provides a cleaner and more structured approach. Using the try and except blocks, a program can watch over a suspicious section of code and, when an error occurs, transfer control to a dedicated handler instead of crashing. This chapter explains what exceptions are, how they arise, how to catch them with try-except, how to raise them deliberately with raise, and how to define custom exceptions.

The chapter is important because robust, professional software never crashes silently. A well-designed program anticipates errors, handles them gracefully, and either recovers or informs the user with a meaningful message. In the board examination, exception handling questions commonly test the syntax of try-except-else-finally, the order of except blocks, the difference between raise and raise from, and the trace of a given program containing an intentional error.

2. What is an Exception?

An exception is a run-time error that occurs when something unexpected happens during program execution. Unlike a syntax error, which is detected by the interpreter before the program starts running, an exception occurs while the program is actually being executed. Examples include dividing a number by zero, trying to convert the string "abc" to an integer, accessing a list index that does not exist, or attempting to open a file that is not present.

Python has many built-in exception classes. Some of the most common ones are listed below.

x = 10 / 0                # ZeroDivisionError
value = int("hello")      # ValueError
lst = [1, 2, 3]
print(lst[5])             # IndexError
d = {"a": 1}
print(d["b"])             # KeyError
num = 5 + "10"            # TypeError

When any of these statements runs, Python raises the corresponding exception and terminates the program unless the exception is handled. The line x = 10 / 0 produces ZeroDivisionError: division by zero.

2.1 Common Built-in Exceptions

The table below summarizes frequently examined exceptions, but a quick list helps here: ZeroDivisionError (division or modulo by zero), ValueError (inappropriate argument value), TypeError (operation applied to an object of inappropriate type), IndexError (sequence index out of range), KeyError (key not found in dictionary), FileNotFoundError (file does not exist), NameError (name not defined), SyntaxError (invalid Python syntax) and OverflowError (numeric result too large to be represented).

print(undefined_variable)   # NameError: name 'undefined_variable' is not defined

3. The try-except Block

The try and except keywords allow a program to handle exceptions gracefully. The code that may cause an exception is placed inside the try block. If an exception occurs, the interpreter immediately jumps to the matching except block and executes its handler. If no exception occurs, the except block is skipped entirely.

try:
    num = int(input("Enter a number: "))
    print(100 / num)
except ZeroDivisionError:
    print("Cannot divide by zero")
except ValueError:
    print("Please enter a valid integer")

In the above program, entering 0 triggers ZeroDivisionError and entering hello triggers ValueError. The single try block can have multiple except blocks, one for each type of exception. The interpreter checks the except blocks in order and executes the first one whose exception type matches.

3.1 Catching All Exceptions

If the exception type is not specified, the except block catches all exceptions. This is convenient but dangerous because it hides unexpected errors and makes debugging difficult.

try:
    result = int("abc")
except:
    print("Something went wrong")

3.2 Using an Exception Object

The keyword as binds the exception to a variable so the program can access its details, such as the message stored in the exception object.

try:
    x = 10 / 0
except ZeroDivisionError as e:
    print("Error message:", e)

4. The else and finally Clauses

A try statement can have optional else and finally clauses. The else block runs only when no exception occurs in the try block, and it must follow all except blocks. The finally block runs unconditionally, whether or not an exception occurred. It is typically used for cleanup actions such as closing a file or releasing a resource.

try:
    num = int(input("Enter a number: "))
    result = 100 / num
except ZeroDivisionError:
    print("Division by zero not allowed")
except ValueError:
    print("Invalid input")
else:
    print("Result:", result)
finally:
    print("Execution of try block completed")

The finally block executes even if a break, continue or return statement is encountered inside the try block, and even if an exception propagates out of the try. This makes it the most reliable place for cleanup code.

5. The raise Statement

Exceptions can be raised deliberately using the raise statement. This is useful for validating input or forcing an error under a specific condition. A built-in exception class and an optional message can be supplied.

marks = int(input("Enter marks: "))
if marks < 0 or marks > 100:
    raise ValueError("Marks must be between 0 and 100")
print("Valid marks:", marks)

The raise statement can also be used inside an except block to re-raise the same exception after logging it, so the caller can handle it. The form raise ValueError("message") from err creates a chained exception that shows the cause.

6. Custom Exceptions

Programmers can define their own exception classes by inheriting from the built-in Exception class. Custom exceptions make code more readable and allow distinct handling of application-specific errors. The class name typically ends with "Error".

class MarksOutOfRangeError(Exception):
    pass

marks = 150
try:
    if marks < 0 or marks > 100:
        raise MarksOutOfRangeError("Marks out of range")
except MarksOutOfRangeError as e:
    print("Custom error caught:", e)

7. Built-in Exception Hierarchy

All built-in exceptions are derived from a common base class, BaseException. The class Exception inherits from BaseException and is the base class of nearly all the exceptions programmers should handle. The hierarchy Exception -> ArithmeticError -> ZeroDivisionError shows, for example, that a ZeroDivisionError is also an ArithmeticError. Because of inheritance, an except block written for a parent class also catches its child exceptions, so a broad except Exception: catches almost every practical error. This is why specific exception types should be listed before general ones.

try:
    x = 10 / 0
except ArithmeticError:
    print("An arithmetic error occurred")

Here the parent class ArithmeticError catches the child ZeroDivisionError.

Quick Revision Tables

Table 1: Common Built-in Exceptions

Exception Cause Example
ZeroDivisionError Division or modulo by zero 10 / 0
ValueError Inappropriate argument value int("abc")
TypeError Operation on wrong type "5" + 5
IndexError Sequence index out of range [1,2,3][9]
KeyError Key not present in dictionary {"a":1}["b"]
FileNotFoundError File does not exist open("nofile.txt")
NameError Name is not defined print(x) when x absent

Table 2: try-except Clauses

Clause When it Executes
try Code monitored for exceptions
except When matching exception occurs
else Only when no exception occurs in try
finally Always, with or without exception

Mind Map

flowchart TD A[Exception Handling] --> B[What is an Exception] A --> C[try-except] C --> C1[Multiple except blocks] C --> C2[as e to read message] C --> C3[Bare except catches all] A --> D[else clause] A --> E[finally clause] A --> F[raise statement] A --> G[Custom Exceptions] G --> G1[Inherit from Exception class] A --> H[Built-in Hierarchy] H --> H1[BaseException] H1 --> H2[Exception] H2 --> H3[ArithmeticError] H3 --> H4[ZeroDivisionError]

Important Diagrams (SVG)

Diagram 1: Flow of try-except-else-finally

try-except-else-finally Flow try block runs Exception? except block runs else block runs finally block runs always Golden Rule: else runs only when no exception occurs; finally always runs.

Diagram 2: Exception Hierarchy

Built-in Exception Hierarchy BaseException Exception ArithmeticError LookupError ValueError ZeroDivisionError IndexError / KeyError A parent except block also catches all its derived exceptions. Golden Rule: Place specific exception handlers before general parent classes.

Common Mistakes

  1. Using a bare except: A bare except: catches every exception including the system KeyboardInterrupt, hiding real bugs and making debugging difficult.
  2. Wrong order of except blocks: Placing a general handler like except Exception before except ZeroDivisionError makes the specific handler unreachable.
  3. Using = instead of == for comparison: Raising or catching is unrelated, but many students confuse raise with raise from, or miswrite the as clause.
  4. Forgetting that else executes only without exception: Putting statements that must run in both cases inside else causes them to be skipped when an exception occurs.
  5. Believing finally is optional for correctness: Code that closes files or releases resources should be placed in finally, otherwise it may never run when an exception interrupts the try.
  6. Raising a non-exception object: raise "error" fails; only exception classes or instances can be raised.
  7. Catching and ignoring silently: An except block that prints nothing makes errors invisible and impossible to trace.
  8. Defining custom exceptions wrongly: A custom exception must inherit from Exception (or a subclass) to behave like a proper exception.

Exam Tips

  1. Memorise the built-in exceptions and their triggers: ZeroDivisionError, ValueError, TypeError, IndexError, KeyError, FileNotFoundError and NameError are the most frequently asked.
  2. Remember the exact order of clauses: try, except, else, finally; the else must come after all except blocks and before finally.
  3. Know the output of a program with an intentional error: practice dry-running a try-except snippet and writing down exactly what is printed.
  4. Learn the syntax of raise: raise ExceptionClassName("message") and remember from err chains the original cause.
  5. Be able to write a custom exception class: one-line classes like class MyError(Exception): pass appear often in 3-mark questions.
  6. Remember that except is skipped if no error occurs and that the first matching handler wins.
  7. Use as e to print the exception message in code-writing questions; it shows careful handling.

Conclusion

Exception handling transforms a fragile program that crashes on bad input into a robust program that responds intelligently to errors. The try-except structure catches exceptions, else distinguishes the success path, and finally guarantees cleanup. The raise statement lets programs generate their own errors, and custom exception classes give applications a readable, domain-specific error vocabulary. Understanding the built-in exception hierarchy helps a programmer write handlers at the right level of generality. Together these tools form the safety net of professional Python programming. In the next chapter, file handling builds on this foundation by teaching how to read and write persistent data, where exception safety becomes especially important because file operations often fail for reasons outside the programmer's control.