Exception Handling in Python
Exception Handling is a mechanism in Python that allows your program to continue running even when unexpected errors occur. Without handling, any runtime error stops the execution and prints a stack trace.
Python uses the following keywords for exception handling:
try– code that may generate an exceptionexcept– handles the exceptionelse– runs if no exception occursfinally– always runs (cleanup code)
1. Basic try-except
Use try when a block may cause an error, and except to handle it.
try:
num = int(input("Enter a number: "))
print("You entered:", num)
except ValueError:
print("Invalid input! Please enter a number.")
If the user inputs text like "abc", int("abc") raises ValueError, and the program continues safely.
2. Handling Multiple Exceptions Separately
Each exception type can be handled independently. Useful when different errors require different messages.
try:
a = int(input("Enter a number: "))
b = int(input("Enter another number: "))
result = a / b
except ValueError:
print("Invalid input! Please enter integers.")
except ZeroDivisionError:
print("Cannot divide by zero!")
Best Practice: Always catch specific exceptions, not generic ones.
3. Catching Multiple Exceptions in One Block
try:
result = int("abc") / 0
except (ValueError, ZeroDivisionError) as e:
print("Error occurred:", e)
Use this when the handling logic is the same for multiple exception types.
4. Using else Block
The else block runs only when no exception occurs.
try:
result = 10 / 2
except ZeroDivisionError:
print("Division by zero!")
else:
print("Division successful, result:", result)
Use Case: Code that should run only if no errors happened.
5. Using finally Block
finally always executes, exceptions or not.
Useful for cleanup operations (closing files, releasing database connections, etc.).
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("File not found!")
finally:
print("Closing file if opened...")
try:
file.close()
except NameError:
pass
Key Point: Even if exception occurs or return is executed, finally still runs.
6. Raising Exceptions Manually
Use raise to throw your own exceptions.
def check_age(age):
if age < 18:
raise ValueError("Age must be at least 18")
return True
try:
check_age(15)
except ValueError as e:
print("Error:", e)
This is useful for validating input or enforcing business rules.
7. Creating Custom Exception Classes
You can create your own exception types by inheriting from Exception.
class NegativeNumberError(Exception):
"""Raised when a negative number is encountered"""
pass
def sqrt(num):
if num < 0:
raise NegativeNumberError("Cannot compute square root of negative number")
return num ** 0.5
try:
print(sqrt(-9))
except NegativeNumberError as e:
print("Custom Error:", e)
Custom exceptions make error handling more meaningful and readable.
8. Common Built-In Exceptions
ValueError– invalid valueTypeError– wrong typeZeroDivisionErrorIndexError– list index out of rangeKeyError– missing dict keyFileNotFoundErrorAttributeError
9. Execution Flow Diagram
try:
# risky code
except:
# runs when error occurs
else:
# runs ONLY if no exception occurs
finally:
# always runs
Flowchart:
+---------+
| try |
+----+----+
|
v
+---------+---------+
| Exception Occurred? |
+----+-----------+---+
| |
Yes No
| |
v v
+-----+----+ +--+-----+
| except | | else |
+-----+----+ +--+-----+
\ /
\ /
\ /
v v
+----+
|finally|
+-------+
10. Nested try-except Example
try:
num = int(input("Enter a number: "))
try:
print(10 / num)
except ZeroDivisionError:
print("Inner: cannot divide by zero!")
except ValueError:
print("Outer: invalid number!")
11. Exception Chaining (raise from)
Use raise ... from ... to show the original cause of an error.
try:
value = int("abc")
except ValueError as e:
raise TypeError("Invalid type conversion") from e
12. Best Practices
- Always catch specific exceptions, not
except: - Use
finallyfor cleanup - Don't swallow exceptions silently
- Create custom exceptions for domain-specific errors
- Log exceptions in real applications