Try / Except
Why Error Handling?
Run this program:
num = int(input("Enter a number: ")) print(f"Double is {num * 2}")
Type "hello" instead of a number. Your program crashes:
ValueError: invalid literal for int() with base 10: 'hello'
Now imagine this is a real app with 10,000 users. One wrong input — entire program crashes. That's a disaster.
Error handling lets your program deal with errors gracefully instead of crashing.
Types of Errors in Python
Before learning how to handle errors, understand the two main types:
1. Syntax Errors — Before program runs
Code is written wrong. Python catches these before even running:
if age >= 18 # SyntaxError: missing colon
print "Hello" # SyntaxError: Python 2 style
You fix these by correcting your code. Error handling cannot catch syntax errors.
2. Exceptions — While program runs
Code is correct but something goes wrong during execution:
int("hello") # ValueError
10 / 0 # ZeroDivisionError
open("ghost.txt") # FileNotFoundError
name # NameError — variable doesn't exist
These are what try/except handles.
Basic try/except
try: # code that might cause an error num = int(input("Enter a number: ")) print(f"Double is {num * 2}") except: # code that runs if ANY error occurs print("Something went wrong! Please enter a valid number.")
Now if user types "hello":
Enter a number: hello
Something went wrong! Please enter a valid number.
Program does NOT crash. It handles the error and continues.
Catching Specific Exceptions
Using bare except: catches everything — too broad. Better to catch specific errors:
try: num = int(input("Enter a number: ")) result = 100 / num print(f"Result: {result}") except ValueError: print("Invalid input — please enter a number, not text") except ZeroDivisionError: print("Cannot divide by zero!")
Now:
- Type "hello" →
ValueErrormessage - Type "0" →
ZeroDivisionErrormessage - Type "5" → works perfectly, prints 20.0
Common Exception Types
|
|---|
else and finally
try/except has two optional extra blocks:
try: num = int(input("Enter a number: ")) result = 100 / num except ValueError: print("Please enter a valid number") except ZeroDivisionError: print("Cannot divide by zero") else: # runs ONLY if no exception occurred print(f"Success! Result is {result}") finally: # runs ALWAYS — whether error or not print("Program finished")
Test with different inputs:
Input "hello":
Please enter a valid number
Program finished
Input "0":
Cannot divide by zero
Program finished
Input "5":
Success! Result is 20.0
Program finished
else — success path, runs only when no error
finally — cleanup code, runs no matter what. Used for closing files, database connections, etc.
Getting Error Details
You can capture the actual error message:
try: num = int("hello") except ValueError as e: print(f"Error occurred: {e}")
Output:
Error occurred: invalid literal for int() with base 10: 'hello'
The as e gives you the error object. e contains the error message. Very useful for debugging.
Catching Multiple Exceptions Together
try: num = int(input("Enter number: ")) result = 100 / num except (ValueError, ZeroDivisionError) as e: print(f"Input error: {e}")
Group exceptions in a tuple when you want to handle them the same way.
Nested try/except
try: with open("data.txt", "r") as file: try: num = int(file.read()) print(f"Number from file: {num}") except ValueError: print("File contains invalid data") except FileNotFoundError: print("data.txt not found")
Outer try handles file errors, inner try handles data errors.
Raising Your Own Exceptions
You can throw errors on purpose using raise:
def set_age(age): if age < 0: raise ValueError("Age cannot be negative") if age > 150: raise ValueError("Age cannot be more than 150") return age
try: age = set_age(-5) except ValueError as e: print(f"Invalid age: {e}")
Output:
Invalid age: Age cannot be negative
This is how you enforce rules in your functions. If someone passes invalid data, you raise an error with a clear message.
Real World Example 1 — Bulletproof Input
This is something every real program needs — keep asking until valid input:
def get_integer(prompt): while True: try: value = int(input(prompt)) return value except ValueError: print("Invalid input. Please enter a whole number.")
def get_positive_integer(prompt): while True: value = get_integer(prompt) if value > 0: return value print("Please enter a positive number.")
def get_float(prompt): while True: try: value = float(input(prompt)) return value except ValueError: print("Invalid input. Please enter a number.")
# Now use these safe input functions age = get_positive_integer("Enter your age: ") salary = get_float("Enter your salary: ")
print(f"\nAge: {age}") print(f"Salary: Rs.{salary:,.2f}")
These helper functions are something you'd keep and reuse in every project. They never crash no matter what the user types.
Real World Example 2 — Safe File Handler
def read_file(filename): try: with open(filename, "r") as file: return file.read() except FileNotFoundError: print(f"Error: '{filename}' not found") return None except PermissionError: print(f"Error: No permission to read '{filename}'") return None
def write_file(filename, content): try: with open(filename, "w") as file: file.write(content) print(f"Successfully saved to '{filename}'") return True except PermissionError: print(f"Error: No permission to write '{filename}'") return False except Exception as e: print(f"Unexpected error: {e}") return False
content = read_file("notes.txt") if content: print(content)
write_file("output.txt", "Hello from Python!")
Real World Example 3 — Calculator with Full Error Handling
Let's upgrade the calculator we built in Stage 3:
def divide(a, b): if b == 0: raise ZeroDivisionError("Cannot divide by zero") return a / b
def get_number(prompt): while True: try: return float(input(prompt)) except ValueError: print("Please enter a valid number")
def calculate(): print("=== Safe Calculator ===")
num1 = get_number("Enter first number: ") num2 = get_number("Enter second number: ")
print("\nChoose operation:") print("1. Add") print("2. Subtract") print("3. Multiply") print("4. Divide")
choice = input("Choice: ")
try: if choice == "1": result = num1 + num2 elif choice == "2": result = num1 - num2 elif choice == "3": result = num1 * num2 elif choice == "4": result = divide(num1, num2) else: raise ValueError("Invalid operation selected")
print(f"\nResult: {result:.4f}")
except ZeroDivisionError as e: print(f"Math error: {e}") except ValueError as e: print(f"Input error: {e}") except Exception as e: print(f"Unexpected error: {e}")
calculate()
This calculator will never crash — every possible error is handled.
Exception Hierarchy
In Python all exceptions are organized in a hierarchy. Exception is the parent of almost all exceptions:
Exception
├── ValueError
├── TypeError
├── ZeroDivisionError
├── FileNotFoundError
├── IndexError
├── KeyError
└── ... and many more
So catching Exception catches almost everything:
try: # some code except Exception as e: print(f"Something went wrong: {e}")
Use this as a last resort — always try to catch specific exceptions first.
Best Practices
1 — Be specific, not general:
# Bad — too broad except: pass
# Good — specific except ValueError: print("Invalid value")
2 — Never silently swallow errors:
# Bad — error is hidden, you'll never know something went wrong try: risky_operation() except: pass
# Good — at least log it try: risky_operation() except Exception as e: print(f"Error: {e}")
3 — Keep try blocks small:
# Bad — too much code in try try: name = input("Name: ") age = int(input("Age: ")) city = input("City: ") process_data(name, age, city) save_to_file(name) except ValueError: pass # which line caused it?
# Good — only the risky part name = input("Name: ") try: age = int(input("Age: ")) except ValueError: print("Age must be a number") city = input("City: ")
Quick Reference
try: # risky code here except ValueError: # handle value errors except ZeroDivisionError: # handle division by zero except FileNotFoundError: # handle missing files except (TypeError, KeyError) as e: # handle multiple exceptions print(f"Error: {e}") except Exception as e: # catch all other exceptions print(f"Unexpected: {e}") else: # runs only if NO exception occurred print("Success!") finally: # always runs print("Done")
# Raise your own exception raise ValueError("Your custom error message")
Exercise 🏋️
Build a Student Marks Manager with full error handling:
- Store student data in a file
marks.txtin this format:
Rahul,85,90,78
Priya,92,88,95
Gagan,75,82,79
- Build a menu:
=== Marks Manager ===
1. View all students
2. Add student
3. Get student average
4. Delete student
5. Exit
Handle ALL these errors properly:
- File not found when loading
- Invalid marks input (non-numbers)
- Student not found when searching
- Duplicate student name when adding
- Invalid menu choice
This exercise combines file handling from Stage 6 with error handling from Stage 7 — two stages in one project!