Python Exception Handling – try, except, finally, raise Explained for Beginners
When you write real Python programs, errors will happen — a user enters wrong input, a file does not exist, or you divide by zero. Without handling these errors, your entire program crashes. Python gives you powerful tools — try, except, else, finally, and raise — to catch errors and keep your program running. This complete guide teaches you everything about Python Exception Handling with clear examples and real-life programs.
Table of Contents
- What is an Exception?
- Common Built-in Exceptions
- try and except – Catch an Error
- Catching Multiple Exceptions
- else Block – Runs When No Error Occurs
- finally Block – Always Runs
- raise – Throw Your Own Exception
- Custom Exception Classes
- Nested try-except
- Real-Life Projects
- Practice Problems
- FAQ
1. What is an Exception in Python?
An exception is an error that occurs while a program is running. When Python encounters something it cannot handle — like dividing by zero, accessing a missing file, or converting text to a number — it stops and raises an exception.
Without exception handling, even a small error will crash your entire program and show an ugly error message to the user. With exception handling, you can catch the error, show a friendly message, and let the program continue.
Without Exception Handling
Program crashes immediately. User sees a confusing error message. All work is lost. Remaining code never runs.
With Exception Handling
Error is caught gracefully. User sees a friendly message. Program continues safely. Remaining code still runs.
# Without handling — program crashes num = int(input("Enter a number: ")) print(10 / num)
Enter a number: 0 ZeroDivisionError: division by zero
2. Common Built-in Exceptions in Python
Python has many built-in exceptions. These are the ones you will see most often as a beginner.
| Exception | When it occurs | Example |
|---|---|---|
ZeroDivisionError | Dividing a number by zero | 10 / 0 |
ValueError | Wrong value type passed to a function | int("abc") |
TypeError | Operation on wrong data type | "hi" + 5 |
NameError | Using an undefined variable | print(x) — x not defined |
IndexError | Accessing index that does not exist | lst[10] on 3-item list |
KeyError | Accessing a key not in a dictionary | d["age"] — key missing |
FileNotFoundError | Opening a file that does not exist | open("x.txt") |
AttributeError | Calling method that does not exist | "hello".push() |
ImportError | Importing a module that is not installed | import xyz |
RecursionError | Too many recursive calls | Missing base case in recursion |
3. try and except – Catch an Error
The try block contains code that might raise an error. The except block runs only if an error actually occurs. If no error happens, the except block is skipped completely.
Basic syntax
try: # Code that might cause an error risky_code() except ExceptionType: # Code that runs if the error occurs handle_the_error()
Example 1 – Catching ZeroDivisionError
try: result = 10 / 0 print(result) except ZeroDivisionError: print("Error: Cannot divide by zero!") print("Program continues normally.")
Error: Cannot divide by zero! Program continues normally.
Example 2 – Catching ValueError from user input
try: age = int(input("Enter your age: ")) print(f"You are {age} years old.") except ValueError: print("Please enter a valid number!")
Enter your age: abc Please enter a valid number!
Getting the error message using "as"
try: nums = [1, 2, 3] print(nums[10]) except IndexError as e: print(f"Error caught: {e}")
Error caught: list index out of range
except ExceptionName as e to capture the actual error message in the variable e. This is very useful for logging errors or showing detailed messages to users.4. Catching Multiple Exceptions
A single try block can have multiple except blocks — one for each type of error. Python checks them from top to bottom and runs the first one that matches.
def safe_divide(a, b): try: result = a / b print(f"Result: {result}") except ZeroDivisionError: print("Error: Cannot divide by zero.") except TypeError: print("Error: Both values must be numbers.") safe_divide(10, 2) safe_divide(10, 0) safe_divide(10, "x")
Result: 5.0 Error: Cannot divide by zero. Error: Both values must be numbers.
Catching multiple exceptions in one line
try: value = int("abc") except (ValueError, TypeError) as e: print(f"Caught: {e}")
Caught: invalid literal for int() with base 10: 'abc'
Catching any exception with bare except
try: x = int(input("Enter number: ")) print(100 / x) except Exception as e: print(f"Something went wrong: {e}")
Enter number: 0 Something went wrong: division by zero
except Exception catches every type of error. This is useful as a catch-all fallback, but always try to catch specific exceptions first. Catching everything can hide bugs that you should actually fix.5. else Block – Runs Only When No Error Occurs
The else block is optional and runs only if the try block completes without raising any exception. Think of it as "if everything went fine, do this."
try: num = int(input("Enter a number: ")) result = 100 / num except ZeroDivisionError: print("Cannot divide by zero!") except ValueError: print("Please enter a valid number!") else: print(f"Success! Result = {result}")
Enter a number: 5 Success! Result = 20.0
else to separate "what to do on success" from the main code. This makes your try-except structure much cleaner and easier to read.6. finally Block – Always Runs No Matter What
The finally block always runs — whether an exception occurred or not. It is used for cleanup operations like closing a file, disconnecting from a database, or releasing resources.
try: print("Opening file...") result = 10 / 2 print(f"Result: {result}") except ZeroDivisionError: print("Division error!") finally: print("Closing file... (always runs)")
Opening file... Result: 5.0 Closing file... (always runs)
# finally runs even when there IS an error try: result = 10 / 0 except ZeroDivisionError: print("Error caught!") finally: print("This always executes.")
Error caught! This always executes.
Complete structure — try + except + else + finally
try: num = int(input("Enter number: ")) result = 100 / num except ValueError: print("Invalid input!") except ZeroDivisionError: print("Cannot divide by zero!") else: print(f"Result = {result}") # Only if no error finally: print("Calculation finished.") # Always
Enter number: 4 Result = 25.0 Calculation finished.
else runs when no exception occurs. The finally always runs last, no matter what happened above.7. raise – Throw Your Own Exception
The raise statement lets you manually trigger an exception. You use it when you want to enforce rules in your program — for example, rejecting invalid input before it causes a problem later.
def check_age(age): if age < 0: raise ValueError("Age cannot be negative!") if age > 150: raise ValueError("Age cannot exceed 150!") print(f"Valid age: {age}") try: check_age(25) check_age(-5) except ValueError as e: print(f"Error: {e}")
Valid age: 25 Error: Age cannot be negative!
8. Custom Exception Classes
You can create your own exception types by defining a class that inherits from Python's built-in Exception class. This makes your code more readable and your errors more meaningful.
# Define custom exception class InsufficientBalanceError(Exception): def __init__(self, balance, amount): self.message = f"Cannot withdraw ₹{amount}. Balance is ₹{balance}." super().__init__(self.message) def withdraw(balance, amount): if amount > balance: raise InsufficientBalanceError(balance, amount) balance -= amount print(f"Withdrawal successful. New balance: ₹{balance}") return balance try: withdraw(1000, 500) withdraw(500, 800) except InsufficientBalanceError as e: print(f"Bank Error: {e}")
Withdrawal successful. New balance: ₹500 Bank Error: Cannot withdraw ₹800. Balance is ₹500.
ValueError, you get a meaningful InsufficientBalanceError that tells you exactly what went wrong.9. Nested try-except
You can place a try-except block inside another try-except block. This is useful when different parts of your code can fail in different ways.
try: num = int(input("Enter a number: ")) try: result = 100 / num print(f"Result: {result}") except ZeroDivisionError: print("Inner error: Division by zero!") except ValueError: print("Outer error: Please enter a valid integer!")
Enter a number: 0 Inner error: Division by zero!
10. Real-Life Projects
Project 1 – Safe Calculator
def calculator(): try: a = float(input("First number: ")) b = float(input("Second number: ")) op = input("Operation (+, -, *, /): ") if op == "+": result = a + b elif op == "-": result = a - b elif op == "*": result = a * b elif op == "/": if b == 0: raise ZeroDivisionError result = a / b else: raise ValueError("Invalid operator") except ValueError as e: print(f"Input error: {e}") except ZeroDivisionError: print("Cannot divide by zero!") else: print(f"Answer: {result}") finally: print("Calculator session ended.\n") calculator()
First number: 10 Second number: 0 Operation (+, -, *, /): / Cannot divide by zero! Calculator session ended.
Project 2 – Login System with Exception Handling
class InvalidCredentialsError(Exception): pass def login(username, password): correct_user = "admin" correct_pass = "python123" if username != correct_user: raise InvalidCredentialsError("Username not found!") if password != correct_pass: raise InvalidCredentialsError("Incorrect password!") return True for attempt in range(1, 4): try: u = input(f"Attempt {attempt} - Username: ") p = input(f"Attempt {attempt} - Password: ") login(u, p) print("Login successful!") break except InvalidCredentialsError as e: print(f"Error: {e}") else: print("Account locked after 3 failed attempts.")
Attempt 1 - Username: admin Attempt 1 - Password: wrongpass Error: Incorrect password! Attempt 2 - Username: admin Attempt 2 - Password: python123 Login successful!
11. Practice Problems
Basic try-except
- Handle division by zero safely
- Handle invalid integer input from user
- Catch IndexError on a list
- Catch KeyError on a dictionary
- Print the actual error message using as
Multiple exceptions
- Handle both ValueError and TypeError
- Use else to run code only on success
- Use finally to print a closing message
- Handle 3 different exceptions in one try
- Use bare Exception to catch everything
raise and custom errors
- Raise ValueError if age is negative
- Raise custom error for invalid password
- Validate username length using raise
- Create NegativeNumberError class
- Raise and catch your custom exception
Real-life challenges
- Safe ATM withdrawal with exception
- Student marks validator (0–100 only)
- Safe file reader with FileNotFoundError
- Login with 3 attempt limit
- Calculator handling all error types
- An exception is a runtime error that stops your program if not handled
trycontains the risky code —excepthandles the error if it occurs- Always catch specific exceptions before using a bare
except Exception elseruns only when the try block completes without any errorfinallyalways runs — perfect for cleanup like closing files or connectionsraiselets you throw your own exception to enforce business rules- Custom exceptions make your code more readable and professional
- Full order: try → except → else → finally
Frequently Asked Questions (FAQ)
Q1. What is the difference between an error and an exception in Python?
An error is a broad term. Syntax errors happen before the program runs — Python cannot even parse the code. Exceptions happen during runtime — the code is valid but something goes wrong while executing. Exception handling only deals with runtime exceptions, not syntax errors.
Q2. Can I have multiple except blocks for one try block?
Yes. You can have as many except blocks as needed. Python checks them from top to bottom and executes the first one that matches the raised exception. After one except block runs, the rest are skipped.
Q3. What is the difference between else and finally in try-except?
The else block runs only when no exception occurred in the try block. The finally block always runs — whether an exception occurred or not. Use else for success logic and finally for cleanup that must always happen.
Q4. When should I use raise in Python?
Use raise when you want to enforce rules in your program. For example, if a function receives a negative age, you can raise a ValueError with a helpful message instead of letting the error appear later in a confusing place.
Q5. What is a custom exception and how do I create one?
A custom exception is a class you define that inherits from Python's built-in Exception class. You create it with class MyError(Exception): pass. Custom exceptions give your errors meaningful names and allow you to carry extra information about what went wrong.
Q6. Does finally run even if there is a return statement in try?
Yes. The finally block runs even if there is a return statement inside the try or except block. Python executes the finally block before actually returning. This guarantees cleanup code always runs.
Found this post helpful? Share it with someone learning Python. Drop your practice solutions in the comments — happy to review them!
"A good program does not just work when everything is perfect — it works gracefully even when things go wrong."
Comments
Post a Comment