Goal: Learn to handle exceptions and write robust programs.
🤔 Why Do Programs Crash?
Imagine you’re writing a calculator. The user enters 10 / 0. The program CRASHES! 💥
number = 10 / 0 # ZeroDivisionError: division by zero
Problem: Python doesn’t know what to do when something goes wrong.
Solution: Teach the program to handle errors using try/except.
🛡️ Basic try/except Syntax
try:
# Risky code that might fail
result = 10 / 0
except:
# What to do if an error occurs
print("An error occurred!")
How it works:
1. Python tries (try) to execute the code
2. If an error occurs, it jumps to the except block
3. The program doesn’t crash — it keeps running!
🎯 Catching Specific Errors
Bad: Catching every possible error blindly
try:
result = int("abc")
except:
print("Error!") # Which error? No idea!
Good: Catching a specific error type
try:
result = int("abc")
except ValueError:
print("That's not a number! Please enter a number.")
Why this matters:
- Different errors call for different responses
- Easier to understand what went wrong
- Code becomes more reliable
📋 Common Exception Types
1. ValueError — invalid value
try:
age = int("twenty") # Can't convert text to a number
except ValueError:
print("Please enter a number as digits!")
When it occurs:
- int("abc") — converting invalid text
- float("xyz") — same for floats
2. ZeroDivisionError — division by zero
try:
result = 100 / 0
except ZeroDivisionError:
print("You can't divide by zero!")
When it occurs:
- Any division by zero
- Mathematical operations with a zero denominator
3. FileNotFoundError — file not found
try:
with open("missing.txt", "r") as f:
data = f.read()
except FileNotFoundError:
print("File not found! Check the path.")
When it occurs:
- Trying to open a non-existent file
- Wrong file path
4. TypeError — wrong data type
try:
result = "5" + 10 # Can't add a string and a number
except TypeError:
print("Incompatible data types!")
When it occurs:
- Operations between incompatible types
- Calling a function with wrong argument types
5. KeyError — key not found in dictionary
try:
user = {"name": "Alice"}
age = user["age"] # Key "age" doesn't exist!
except KeyError:
print("That key doesn't exist in the dictionary!")
When it occurs:
- Accessing a non-existent dictionary key
- Trying to retrieve a value for a missing key
6. IndexError — index out of range
try:
numbers = [1, 2, 3]
print(numbers[10]) # Index 10 doesn't exist!
except IndexError:
print("Index is out of range!")
When it occurs:
- Accessing a non-existent list index
- Trying to retrieve an element beyond the list bounds
🎭 Multiple except Blocks
Handle different errors differently:
try:
age = int(input("Your age: "))
result = 100 / age
except ValueError:
print("Please enter a number!")
except ZeroDivisionError:
print("Age can't be zero!")
Order matters:
- Specific exceptions first
- More general ones after (if needed)
📦 Getting Error Details
try:
number = int("abc")
except ValueError as e:
print(f"Error: {e}")
# Output: Error: invalid literal for int() with base 10: 'abc'
The variable e:
- Contains the exception object
- Lets you print details
- Useful for logging
🧹 The finally Block — Always Runs
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("File not found!")
finally:
print("This code always runs")
# Close the file, release resources, etc.
When to use finally:
- Closing files
- Releasing resources
- Cleaning up temporary data
- Code that must run regardless of errors
Example with files:
file = None
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("File not found!")
finally:
if file:
file.close() # Guaranteed to close the file
Note: With
with open(),finallyis unnecessary — the file closes automatically!
🔄 The else Block — No Errors Occurred
try:
age = int(input("Age: "))
except ValueError:
print("That's not a number!")
else:
print(f"Your age: {age}")
# Executes only if NO error occurred
When to use else:
- Code that should run only on success
- Logic that depends on a successful try
⚠️ When NOT to Use try/except
❌ Bad: Hiding problems
try:
hacky_code_here()
except:
pass # Silently ignore all errors — BAD!
Why it’s bad:
- Hides real bugs in the code
- Makes debugging very hard
- Can lead to unpredictable behavior
❌ Bad: Replacing explicit checks
# Bad
try:
if user["age"] > 18:
print("Adult")
except KeyError:
print("Age unknown")
# Good
if "age" in user and user["age"] > 18:
print("Adult")
else:
print("Age unknown")
Rule: If you can check a condition before an error occurs, do that instead!
✅ When to Use try/except
✅ File I/O
try:
with open("data.txt", "r") as f:
data = f.read()
except FileNotFoundError:
print("Creating a new file...")
with open("data.txt", "w") as f:
f.write("Initial data")
✅ User Input
while True:
try:
age = int(input("Enter age: "))
break # Success! Exit the loop
except ValueError:
print("That's not a number! Please try again.")
✅ Network/API Calls
try:
response = api.get_data()
except ConnectionError:
print("No internet connection!")
except TimeoutError:
print("Server is not responding!")
✅ Data Conversion
try:
data = json.loads(json_string)
except json.JSONDecodeError:
print("Invalid JSON!")
🎯 Pattern: Safe Input
Task: Keep prompting for a number until the user enters a valid one.
def get_number(prompt):
"""Safely read a number with retry on bad input."""
while True:
try:
value = int(input(prompt))
return value # Success! Return the number
except ValueError:
print("Error! Please enter an integer.")
# Usage
age = get_number("Enter your age: ")
print(f"You are {age} years old")
Benefits:
- Program doesn’t crash
- User gets clear feedback
- Input can be retried
🎯 Pattern: Default Value
def get_setting(key, default=None):
"""Retrieve a setting or return a default value."""
try:
with open("settings.json", "r") as f:
settings = json.load(f)
return settings[key]
except (FileNotFoundError, KeyError):
return default
# Usage
theme = get_setting("theme", "dark") # Returns "dark" if file doesn't exist
🎯 Pattern: Retry
def save_data(data, attempts=3):
"""Save data with retries."""
for attempt in range(attempts):
try:
with open("data.json", "w") as f:
json.dump(data, f)
print("Data saved!")
return True
except IOError:
print(f"Attempt {attempt + 1} failed...")
print("Failed to save data!")
return False
⚡ Best Practices
✅ Do:
- Catch specific exceptions (
except ValueError:) - Give clear error messages (“Enter a number between 1 and 100”)
- Log errors (print or write to a file)
- Use finally for resource cleanup
- Keep the try block narrow (only the risky code)
❌ Don’t:
- Avoid bare except: (without specifying the error type)
- Don’t silently swallow errors (
except: pass) - Don’t make try too wide (wrapping all your code in try)
- Don’t hide bugs (using try/except instead of fixing the root cause)
📝 Example: Bank Account Validation
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def deposit(self, amount):
"""Deposit funds."""
try:
amount = float(amount) # Convert to a number
if amount <= 0:
print("Amount must be positive!")
return False
self.balance += amount
print(f"Deposited: {amount}. Balance: {self.balance}.")
return True
except ValueError:
print("Please enter a number!")
return False
def withdraw(self, amount):
"""Withdraw funds."""
try:
amount = float(amount)
if amount <= 0:
print("Amount must be positive!")
return False
if amount > self.balance:
print("Insufficient funds!")
return False
self.balance -= amount
print(f"Withdrawn: {amount}. Remaining: {self.balance}.")
return True
except ValueError:
print("Please enter a number!")
return False
# Usage
account = BankAccount(1000)
account.deposit("500") # OK
account.deposit("abc") # Validation error
account.withdraw("2000") # Insufficient funds
account.withdraw("300") # OK
🎓 Summary
try/except:
- ✅ Prevents the program from crashing
- ✅ Handles unpredictable situations
- ✅ Improves user experience
- ✅ Makes code more reliable
Golden rule: Use try/except where you can’t predict the outcome (user input, files, network), but don’t use it instead of regular checks!
Structure:
try:
# Risky code
...
except SpecificError:
# Handle a specific error
...
except AnotherError as e:
# Handle another error
print(f"Error: {e}")
else:
# Executes if no error occurred
...
finally:
# Always executes
...
🔗 Related Topics
Now your code doesn’t crash — it handles errors gracefully! 🛡️
💬 Comments (0)
No comments yet
Be the first to share your opinion about this article!