Exception Handling
Introduction
áᎠchapter áážáŹááąáŹáˇ program ááąáŤááşááŹá error áááşááŹáá˝áąááᯠáááşááᯠhandle ááŻááşááá˛áááŻááŹááᯠáá˝áąáˇáááŤáááşá
Real-world áážáŹ program áá˝áąá áĄááźá˛áááşá¸ áááťážáąáŹáşáááˇáşáá˛áˇ áĄááŹáá˝áąáá˛áˇ ááźáŻáśááááş:
- User á ááśááŤááş áááˇáşááážáŹááᯠá áŹááŻáśá¸ áááˇáşááŹ
- File áááşááťááşáᏠfile ááážááá°á¸
- Network connection ááźááşáá˝áŹá¸ááŹ
- Zero áá˛áˇ á áŹá¸ááááŹ
- Dictionary áážáŹ ááážááá˛áˇ key ááąáŤáşááŹ
áĄá˛áˇááᯠáĄááŹáá˝áąááᯠException (ááťá˝ááşá¸ááťááş) áááŻáˇ ááąáŤáşáááşá Exception Handling á program ááąáŤááşááá˝áŹá¸áĄáąáŹááşá áááşááá˝áŹá¸áĄáąáŹááş gracefully handle ááŻááşáááŻáˇáá˛á
Exception áááŻááŹ?
Exception áááŻáᏠprogram run ááąááŻááşá¸ ááááşáážááşáᲠááźá áşááŹáá˛áˇ error áá áşááŻá
Without Exception Handling:
# User ááᯠááśááŤááş áááˇáşáááŻááşá¸áááş
age = int(input("áĄáááş áááˇáşááŤ: "))
print(f"bro áĄáááş {age} áážá
áş")
# User á "abc" áááˇáşáááŻááşáááş?
# ValueError: invalid literal for int() with base 10: 'abc'
# Program ááá˝áŹá¸áááŻááşáááş!With Exception Handling:
try:
age = int(input("áĄáááş áááˇáşááŤ: "))
print(f"bro áĄáááş {age} áážá
áş")
except ValueError:
print("ááśááŤááşáᲠáááˇáşá፠bro!")
# User á "abc" áááˇáşáááşá¸ error ááááşááąáŹáˇáá°á¸á
# áá°áˇááᯠmessage áážáážááąá¸ ááźááźáŽá¸ áááşáá˝áŹá¸áááş- Program ááąáŤááşááá˝áŹá¸áĄáąáŹááş ááŹáá˝ááşááŹá error áááşáááşá¸ program ááááşááąáŹáˇáá°á¸á
- User ááᯠáĄáááşááźáąáá˛áˇ error message ááźááŹ
- Cleanup operations (file close, connection close) ááŻááşááŹ
- Program ááᯠstable ááźá áşáĄáąáŹááş ááŻááşááŹ
Basic try-except
áĄáááŻá¸áážááşá¸ááŻáśá¸ exception handling structure á try-except ááąáŤáˇá
Syntax:
try:
# error ááźá
áşáááŻááşáá˛áˇ code
pass
except ExceptionType:
# error ááźá
áşáááş ááŻááşáááˇáş code
passExample 1: Division by Zero
try:
result = 10 / 0
print(result)
except ZeroDivisionError:
print("ááŻááá˛áˇ áá
áŹá¸áá˛áˇ bro!")Example 2: Type Conversion Error
try:
number = int("abc")
print(number)
except ValueError:
print("á
áŹááŻáśá¸ááᯠááśááŤááş áááźáąáŹááşá¸áááŻáˇááá°á¸!")Example 3: Getting Exception Details
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
print(f"Error type: {type(e)}")Output:
Error: division by zero
Error type: <class 'ZeroDivisionError'>The Complete Squad: try-except-else-finally
Exception handling áá˛áˇ áĄááźááˇáşáĄá áŻáś structure áážáŹ áĄáááŻááşá¸ á áááŻááşá¸ áážááááşá
Structure:
try:
# error ááźá
áşáááŻááşáá˛áˇ code (á
ááşá¸ááźááˇáşáááˇáş code)
pass
except ExceptionType:
# error ááźá
áşáááş run áááş (error áááşá¸áááş)
pass
else:
# error áááźá
áşáááş run áááş (áĄáááşááźáąáááş run áááş)
pass
finally:
# error ááźá
áşááźá
áş áááźá
áşááźá
áş áĄááźá˛ run áááş (cleanup)
passDetailed Explanation:
- try: error ááźá áşáááŻááşáá˛áˇ code ááᯠá ááşá¸ááźááˇáşáááş
- except: error ááźá áşáááş áᎠblock run áááş (error áĄáááşá¸áááŹá¸)
- else: error áááźá áşáᲠáĄáááşááźáąáááş áᎠblock run áááş (áĄáąá¸ááąá¸áááŹá¸)
- finally: ááŹáá˛ááźá áşááźá áş áĄááźá˛ run áááş (ááŹáááşááťáąáááŹá¸ - cleanup áĄáá˝ááş)
Complete Example:
try:
print("1. try block: á
ááşá¸ááźááˇáşááąáááş...")
age = int(input("áĄáááş áááˇáşááŤ: "))
result = 100 / age
except ValueError:
print("2. except block: ááśááŤááşáᲠáááˇáşá፠bro!")
except ZeroDivisionError:
print("2. except block: ááŻááá˛áˇ áá
áŹá¸áá˛áˇ!")
else:
print(f"3. else block: áĄáááşááźáąáááş! Result = {result}")
finally:
print("4. finally block: á፠áĄááźá˛ run áááş!")Test Cases:
1. try block: á
ááşá¸ááźááˇáşááąáááş...
áĄáááş áááˇáşááŤ: 20
3. else block: áĄáááşááźáąáááş! Result = 5.0
4. finally block: á፠áĄááźá˛ run áááş!1. try block: á
ááşá¸ááźááˇáşááąáááş...
áĄáááş áááˇáşááŤ: abc
2. except block: ááśááŤááşáᲠáááˇáşá፠bro!
4. finally block: á፠áĄááźá˛ run áááş!1. try block: á
ááşá¸ááźááˇáşááąáááş...
áĄáááş áááˇáşááŤ: 0
2. except block: ááŻááá˛áˇ áá
áŹá¸áá˛áˇ!
4. finally block: á፠áĄááźá˛ run áááş!finally for File Handling:
f = None
try:
f = open("data.txt", "r")
content = f.read()
print(content)
except FileNotFoundError:
print("File ááážááá°á¸")
finally:
# error ááźá
áşááźá
áş áááźá
áşááźá
áş file ááᯠááááşááááş
if f:
f.close()
print("File ááááşááźáŽá¸")elseblock á error áááźá áşááž run áááşfinallyblock á ááŹáá˛ááźá áşááźá áş áĄááźá˛ run áááşfinallyááᯠfile close, connection close á áá˛áˇ cleanup áĄáá˝ááş ááŻáśá¸áááş
Built-in Exceptions
Python áážáŹ ááŤááŹáá˛áˇ exception áĄááťááŻá¸áĄá áŹá¸áá˝áą áĄááťáŹá¸ááźáŽá¸ áážááááşá
Common Built-in Exceptions:
1. ValueError:
áááşáááŻá¸á áážááşááąáááˇáş áĄááťááŻá¸áĄá áŹá¸ ááážááşááŹ
try:
number = int("abc") # string ááᯠint áááźáąáŹááşá¸áááŻáˇááá°á¸
except ValueError as e:
print(f"ValueError: {e}")
try:
number = int("12.5") # decimal string ááᯠint áááźáąáŹááşá¸áááŻáˇááá°á¸
except ValueError as e:
print(f"ValueError: {e}")2. TypeError:
ááá°ááŽáá˛áˇ type áá˝áąááᯠáá˝á˛ááŻáśá¸ááŹ
try:
result = "Hello" + 5 # str áá˛áˇ int ááąáŤááşá¸áááŻáˇáááá°á¸
except TypeError as e:
print(f"TypeError: {e}")
try:
result = len(123) # int áážáŹ length ááážááá°á¸
except TypeError as e:
print(f"TypeError: {e}")3. ZeroDivisionError:
ááŻááá˛áˇ á áŹá¸ááŹ
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"ZeroDivisionError: {e}")
try:
result = 10 % 0 # modulo áážáŹáááşá¸ error
except ZeroDivisionError as e:
print(f"ZeroDivisionError: {e}")4. FileNotFoundError:
File áážáŹááá˝áąáˇááŹ
try:
with open("missing_file.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
print(f"FileNotFoundError: {e}")
print("File ááážáááŤáá°á¸")5. KeyError:
Dictionary áážáŹ ááážááá˛áˇ key ááąáŤáşááŹ
person = {"name": "ááąáŹááşááąáŹááş", "age": 25}
try:
city = person["city"] # "city" key ááážááá°á¸
except KeyError as e:
print(f"KeyError: {e}")
print("Key ááážáááŤáá°á¸")
# Better way: use .get() method
city = person.get("city", "Unknown")
print(f"City: {city}")6. IndexError:
List/Tuple index á range áĄááźááşáážáŹ áážáááŹ
numbers = [1, 2, 3]
try:
value = numbers[5] # index 5 ááážááá°á¸
except IndexError as e:
print(f"IndexError: {e}")
print("Index á list áá˛áˇ size áááş ááźáŽá¸ááąáááş")7. AttributeError:
Object áážáŹ ááážááá˛áˇ attribute/method ááąáŤáşááŹ
try:
text = "Hello"
result = text.append("World") # str áážáŹ append() ááážááá°á¸
except AttributeError as e:
print(f"AttributeError: {e}")
print("str áážáŹ append method ááážááá°á¸")8. ImportError / ModuleNotFoundError:
Module import ááŻááşáááŻáˇ ááááŹ
try:
import non_existent_module
except ModuleNotFoundError as e:
print(f"ModuleNotFoundError: {e}")
print("Module ááá˝áąáˇáá°á¸á pip install ááŻááşáááŻáˇ áááŻáááŻááşáááş")9. NameError:
ááážááá˛áˇ variable ááᯠááŻáśá¸ááŹ
try:
print(undefined_variable) # áᎠvariable ááᯠdeclare áááŻááşááŹá¸áá°á¸
except NameError as e:
print(f"NameError: {e}")
print("Variable ááᯠdefine áááŻááşááŹá¸áá°á¸")Multiple Exception Handling
Exception áá˝áąááᯠáááşááᯠhandle ááŻááşááá˛á
Method 1: Multiple Exceptions in One Block
try:
value = int(input("ááśááŤááş áááˇáşááŤ: "))
result = 100 / value
except (ValueError, ZeroDivisionError) as e:
print(f"Error ááźá
áşáá˝áŹá¸áááş: {e}")
print("ááśááŤááş áážááşáážááş áááˇáş (ááŻá áááŻááşááŹ)")Method 2: Separate Exception Blocks
try:
value = int(input("ááśááŤááş áááˇáşááŤ: "))
result = 100 / value
print(f"Result: {result}")
except ValueError:
print("ááśááŤááşáᲠáááˇáşááŤ!")
except ZeroDivisionError:
print("ááŻááá˛áˇ áá
áŹá¸áá˛áˇ!")Method 3: With Generic Catch-All
try:
value = int(input("ááśááŤááş áááˇáşááŤ: "))
result = 100 / value
print(f"Result: {result}")
except ValueError:
print("ááśááŤááşáᲠáááˇáşááŤ!")
except ZeroDivisionError:
print("ááŻááá˛áˇ áá
áŹá¸áá˛áˇ!")
except Exception as e:
# ááááşááŹá¸áá˛áˇ áááźáŹá¸ error áá˝áąáĄáá˝ááş
print(f"ááťážáąáŹáşáááˇáşáááŹá¸áá˛áˇ error: {e}")- Specific exceptions áá˝áąááᯠáĄáááş catch ááŻááşááŤ
- Generic
ExceptionááᯠááąáŹááşááŻáśá¸áážáŹáᲠááŻáśá¸
Raising Exceptions
áááŻááˇáşááŹáᏠáááŻááş exception áá áşáááŻáˇááááşá
Basic raise:
def check_age(age):
if age < 0:
raise ValueError("áĄáááşá áĄááŻááş áááźá
áşáááŻááşáá°á¸")
elif age < 18:
raise ValueError("áá áážá
áşáĄáąáŹááş áááşáááá°á¸")
else:
print(f"Welcome! áĄáááş {age} áážá
áş")
# Test
try:
check_age(15)
except ValueError as e:
print(f"Error: {e}")Re-raising Exceptions:
def process_file(filename):
try:
with open(filename, "r") as f:
data = f.read()
return data
except FileNotFoundError:
print(f"Logging: {filename} ááážááá°á¸")
raise # Exception ááᯠááźááşáá
áşáááş
try:
process_file("missing.txt")
except FileNotFoundError:
print("Main: File error ááᯠhandle ááŻááşááąáááş")Output:
Logging: missing.txt ááážááá°á¸
Main: File error ááᯠhandle ááŻááşááąáááşException Chaining (raise...from):
def load_config(filename):
try:
with open(filename) as f:
data = f.read()
return data
except FileNotFoundError as e:
# Original exception ááᯠáá°ááźáŽá¸ new exception áá
áşáááş
raise RuntimeError("Config file á load áááŻáˇáááá°á¸") from e
try:
load_config("config.txt")
except RuntimeError as e:
print(f"Error: {e}")
print(f"Original cause: {e.__cause__}")Custom Exceptions
áááŻááşáááŻááş exception class áá˝áąáááşá¸ ááąáŹááşáááŻáˇáááąá¸áááşá
Simple Custom Exception:
class InvalidAgeError(Exception):
"""áĄáááş ááážááşáá˛áˇáĄá፠ááŻáśá¸áááˇáş exception"""
pass
def register_user(name, age):
if age < 18:
raise InvalidAgeError(f"{name} á áááşáá˝ááşá¸áááş (áĄáááş: {age})")
print(f"{name} ááᯠregister ááŻááşááźáŽá¸")
try:
register_user("ááąáŹááşááąáŹááş", 15)
except InvalidAgeError as e:
print(f"Registration Error: {e}")Custom Exception with Attributes:
class InsufficientBalanceError(Exception):
"""áá˝áąáááşááťááş áááŻáśááąáŹááşáá˛áˇáĄááŤ"""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
self.shortage = amount - balance
message = f"áááşááťááş áááŻáśááąáŹááşáá°á¸á áááŻáĄááşááŹ: {amount}, áážáááŹ: {balance}"
super().__init__(message)
def withdraw(balance, amount):
if amount > balance:
raise InsufficientBalanceError(balance, amount)
return balance - amount
try:
new_balance = withdraw(1000, 1500)
except InsufficientBalanceError as e:
print(f"Error: {e}")
print(f"áááŻáĄááşááąá¸ááŹ: {e.shortage} ááťááş")Exception Hierarchy:
class PaymentError(Exception):
"""Payment error áĄáŹá¸ááŻáśá¸áá˛áˇ base class"""
pass
class InsufficientFundsError(PaymentError):
"""áá˝áąáááŻáśááąáŹááşáá˛áˇ error"""
pass
class InvalidCardError(PaymentError):
"""Card ááážááşáá˛áˇ error"""
pass
def process_payment(amount, card_valid):
if not card_valid:
raise InvalidCardError("Card ááᯠverify ááŻááşáá")
if amount > 5000:
raise InsufficientFundsError("áá˝áąáááŻáśááąáŹááşáá°á¸")
print("Payment áĄáąáŹááşááźááşááŤáááş")
# Base exception áá˛áˇ catch ááŻááşáááŻáˇááááş
try:
process_payment(6000, True)
except PaymentError as e:
print(f"Payment Error: {e}")Assertions (assert statement)
Assert á debugging áĄáá˝ááş ááŻáśá¸ááŹá Condition ááážááşáááş AssertionError áá áşáááşá
Basic assert:
def divide(a, b):
assert b != 0, "Divisor á ááŻá ááźá
áşáá"
return a / b
print(divide(10, 2)) # OK
try:
print(divide(10, 0)) # AssertionError
except AssertionError as e:
print(f"Assertion failed: {e}")Assert for Validation:
def calculate_average(scores):
assert len(scores) > 0, "Scores list á empty ááźá
áşáááŻáˇáááá°á¸"
assert all(isinstance(s, (int, float)) for s in scores), "áĄááŻááşá numbers ááźá
áşááááş"
return sum(scores) / len(scores)
# Test
print(calculate_average([85, 90, 92])) # OK
try:
print(calculate_average([])) # AssertionError
except AssertionError as e:
print(f"Error: {e}")- Assert á development/testing áĄáá˝ááşáᲠááŻáśá¸ááąáŹáş
- Production code áážáŹ error handling áĄá á áşáá˝ááş try-except áááŻáá˛ááŻáśá¸
- Python áááŻ
-O(optimize) flag áá˛áˇ run áááş assert áá˝áą ignore ááŻááşáááş
Logging with Exception Handling
Exception áá˝áąááᯠlog file áážáŹ áážááşááŹá¸áááŻáˇááááşá
Basic Logging:
import logging
# Logging setup
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='app.log'
)
try:
result = 10 / 0
except ZeroDivisionError as e:
logging.error(f"Error occurred: {e}")
print("Error logged to app.log")Logging with Traceback:
import logging
logging.basicConfig(
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='errors.log'
)
def divide_numbers(a, b):
try:
return a / b
except ZeroDivisionError:
logging.exception("Division by zero attempted")
raise
try:
result = divide_numbers(10, 0)
except ZeroDivisionError:
print("Error logged with full traceback")Complete Logging Example:
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('application.log'),
logging.StreamHandler() # Console áážáŹáááşá¸ ááźáááş
]
)
logger = logging.getLogger(__name__)
def process_data(data):
try:
logger.info("Processing data started")
# Simulate processing
result = 100 / data
logger.info(f"Processing completed. Result: {result}")
return result
except ZeroDivisionError:
logger.error("Cannot divide by zero", exc_info=True)
return None
except Exception as e:
logger.exception("Unexpected error occurred")
return None
# Test
process_data(10) # Success
process_data(0) # ErrorPractical Examples
Example 1: File Reader with Multiple Exceptions
def read_file_safely(filename):
"""File ááᯠááąá¸áááşá¸áááşá¸ áááşáááş"""
try:
with open(filename, "r", encoding="utf-8") as f:
content = f.read()
print(f"File size: {len(content)} characters")
return content
except FileNotFoundError:
print(f"Error: {filename} ááᯠáážáŹááá˝áąáˇáá°á¸")
return None
except PermissionError:
print(f"Error: {filename} ááᯠáááşáá˝ááˇáş ááážááá°á¸")
return None
except UnicodeDecodeError:
print(f"Error: {filename} á UTF-8 áááŻááşáá°á¸")
# Try with different encoding
try:
with open(filename, "r", encoding="latin-1") as f:
return f.read()
except:
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
else:
print("File ááᯠáááşááźáŽá¸ááźáŽá¸")
finally:
print(f"File operation completed for {filename}")
# Test
content = read_file_safely("test.txt")
if content:
print(f"Content: {content[:50]}...")Example 2: User Input Validator
def get_integer_input(prompt, min_value=None, max_value=None):
"""User áááą integer input áá°áááş (validation áá˛áˇ)"""
while True:
try:
value = int(input(prompt))
# Range validation
if min_value is not None and value < min_value:
print(f"áááşáááŻá¸á {min_value} áááş ááźáŽá¸ááááş")
continue
if max_value is not None and value > max_value:
print(f"áááşáááŻá¸á {max_value} áááş ááąá¸ááááş")
continue
return value
except ValueError:
print("ááśááŤááşáᲠáááˇáşááŤ!")
except KeyboardInterrupt:
print("\nUser á cancel ááŻááşáááŻááşááźáŽ")
return None
# Test
age = get_integer_input("áĄáááş áááˇáşá፠(18-100): ", 18, 100)
if age:
print(f"áĄáááş: {age} áážá
áş")Suggestions
1. Be Specific with Exceptions:
# Bad
try:
value = int(input("Number: "))
except: # Catches everything
print("Error")
# áá˝ááş
try:
value = int(input("Number: "))
except ValueError:
print("Please enter a valid number")
except KeyboardInterrupt:
print("\nCancelled by user")2. Don't Swallow Errors:
# Bad
try:
risky_operation()
except:
pass # Error ááᯠskip ááááŻááşááŹ!
# áá˝ááş
import logging
try:
risky_operation()
except Exception as e:
logging.error(f"Operation failed: {e}")
# Or re-raise
raise3. Use else and finally Appropriately:
# Good pattern
try:
f = open("file.txt", "r")
except FileNotFoundError:
print("File not found")
else:
# Only runs if no exception
content = f.read()
print(content)
finally:
# Always runs - cleanup
if 'f' in locals():
f.close()4. Provide Meaningful Error Messages:
# Bad
try:
age = int(input("Age: "))
except ValueError:
print("Error")
# áá˝ááş
try:
age = int(input("Age: "))
except ValueError:
print("Invalid input. Please enter your age as a number (e.g., 25)")áĄáážá áşááťáŻááş
Exception Handling áĄááźáąáŹááşá¸ ááźáŽá¸ááŤááźáŽá
Key Concepts:
- try: Error ááźá áşáááŻááşáá˛áˇ code ááąá¸ááŹ
- except: Error ááᯠhandle ááŻááşááŹ
- else: Error áááźá áşáááş run áááˇáş code
- finally: ááŹáá˛ááźá áşááźá áş áĄááźá˛ run áááˇáş code (cleanup)
- raise: Exception áá áşááŹ
- Custom Exceptions: áááŻááşáááŻááş exception class áá˝áą
- assert: Debugging áĄáá˝ááş condition check ááŻááşááŹ
Built-in Exceptions:
- ValueError, TypeError, ZeroDivisionError
- FileNotFoundError, KeyError, IndexError
- AttributeError, ImportError, NameError
Best Practices:
- Specific exceptions áá˝áąááᯠcatch ááŻááşááŤ
- Error áá˝áąááᯠsilent áááźá áşáĄáąáŹááşááŻááşáááşáˇáááş
- User ááᯠclear error message ááźááąá¸
- finally ááᯠcleanup áĄáá˝ááş ááŻáśá¸ááąáŤáˇá áááŻáśá¸áááąá ááŻáśá áśááťááŻá¸ááąáŹáˇáááŻááşá
Quick Reference
# === Basic Structure ===
try:
# risky code
except ExceptionType:
# handle error
else:
# no error
finally:
# always runs
# === Multiple Exceptions ===
except (ValueError, TypeError):
pass
# === Get Exception Details ===
except ValueError as e:
print(e)
# === Raise Exception ===
raise ValueError("Error message")
# === Re-raise ===
except ValueError:
# do something
raise
# === Custom Exception ===
class MyError(Exception):
pass
# === Assert ===
assert condition, "message"
# === Logging ===
import logging
logging.exception("Error occurred")
# === Context Manager ===
with open("file.txt") as f:
data = f.read()
# === Suppress ===
from contextlib import suppress
with suppress(FileNotFoundError):
open("file.txt")