0% found this document useful (0 votes)
10 views8 pages

Error Handling

Uploaded by

alibasajonel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views8 pages

Error Handling

Uploaded by

alibasajonel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 8

1. What Are Exceptions?

Exceptions are Python’s way of signaling that something went wrong at


runtime.

When an error occurs, Python raises an exception object. If it isn’t caught,


the program terminates with a traceback.

Common built-in exceptions:

SyntaxError, NameError, TypeError, ValueError, KeyError, IndexError,


IOError/OSError, ZeroDivisionError, etc.

2. The Exception Hierarchy

Python’s exceptions form a class hierarchy rooted at BaseException:

BaseException

└── Exception

├── ArithmeticError

│ ├── ZeroDivisionError

│ └── OverflowError

├── LookupError

│ ├── IndexError

│ └── KeyError

├── OSError

├── ValueError

├── TypeError

└── …and many more…

Catch broadly by catching Exception (but avoid catching BaseException,


which also includes KeyboardInterrupt, SystemExit).
Catch narrowly by catching specific subclasses to avoid hiding bugs.

3. Basic try / except

try:

result = 10 / int(input("Divide 10 by: "))

except ZeroDivisionError:

print("Cannot divide by zero!")

except ValueError:

print("Please enter a valid integer.")

else:

print("Result is", result)

try block: code that may raise.

except <ExceptionType>: handles that type.

You can have multiple except clauses in order from specific to general.

except Exception: catches all standard exceptions.

4. else and finally

try:

f = open("data.txt")

data = f.read()

except OSError as e:

print("File error:", e)

else:

print("File contents:", data)


finally:

# Always runs, even if no exception or after handling one

f.close()

else runs if the try block succeeded (no exception).

finally always runs, even if an exception is uncaught or re-raised—ideal for


cleanup.

5. Catching Multiple Exceptions

try:

x = int(data["value"])

y = 10 / x

except (KeyError, ValueError):

print("Missing or invalid 'value' in data.")

except ZeroDivisionError:

print("'value' must not be zero.")

Use a tuple in except to handle several error types with one handler.

If you need different handling for each, separate them into multiple except.

6. Raising Exceptions

You can raise exceptions yourself using raise:

def withdraw(balance, amount):

if amount > balance:

raise ValueError(f"Insufficient funds: {amount} > {balance}")

return balance - amount


raise ExceptionType("message") throws a new exception.

Without arguments, raise re-raises the current exception inside an except


block.

7. Custom Exceptions

Define your own for clearer domain-specific errors:

class CropRecommenderError(Exception):

"""Base exception for our crop recommender system."""

pass

class InvalidSoilData(CropRecommenderError):

"""Raised when soil parameters are out of realistic range."""

pass

def recommend(n, p, k):

if not (0 <= n <= 200):

raise InvalidSoilData(f"Nitrogen {n} out of range")

# … rest of logic …

Inherit from Exception or a subclass.

Give meaningful names and docstrings.

8. Exception Chaining

When catching one exception and wanting to raise another, preserve


context:
try:

user = load_user(uid)

except DatabaseError as db_err:

raise RuntimeError("Failed to load user profile") from db_err

The from keyword links the new exception to the original, so tracebacks show
both.

9. Context Managers & Exceptions

Use the with statement to manage resources safely:

with open("log.txt", "a") as log:

log.write("Starting process\n")

# if an exception occurs, file is still closed properly

You can write your own by implementing __enter__ and __exit__:

class Timer:

def __enter__(self):

import time

self.start = time.time()

return self

def __exit__(self, exc_type, exc, tb):

import time

print("Elapsed:", time.time() - self.start)

with Timer():

do_heavy_work()

In __exit__, returning True suppresses the exception; normally you let it


propagate.
10. Best Practices

Don’t catch “everything.”

Avoid bare except: or catching Exception unless truly necessary.

Handle only what you can recover from.

Let unexpected exceptions bubble up to fail fast.

Clean up resources.

Use with or finally to close files, network connections, locks, etc.

Log meaningful context.

Combine exceptions with logging:

import logging

logger = logging.getLogger(__name__)

try:

except Exception as e:

logger.exception("Processing failed for input %r", data)

raise

Validate inputs early.

Use guard clauses and custom exceptions rather than letting code fail deep
inside.

Document your exceptions.

In docstrings, list what exceptions a function may raise.

11. Debugging Tips


Read the traceback. It pinpoints where the error happened.

Use pdb (Python debugger) to step through code at the exception site:

python -m pdb your_script.py

Interactive exploration: Catch exceptions and inspect state.

Assertions (assert x > 0) are useful for sanity checks but can be disabled
with optimization flags—don’t rely on them for essential error handling.

12. Real-World Example: Safe HTTP Request

import requests

def fetch_json(url):

try:

resp = requests.get(url, timeout=5)

resp.raise_for_status() # raises HTTPError for 4xx/5xx

except requests.Timeout:

print("Request timed out")

except requests.HTTPError as http_err:

print("HTTP error:", http_err)

except requests.RequestException as req_err:

print("Network error:", req_err)

else:

return resp.json()

return None

Differentiates network timeouts, HTTP errors, and other request issues.


Uses else for the successful path and returns None on failure.

Summary

Understand Python’s exception hierarchy.

Use try/except/else/finally to structure error handling.

Raise and define custom exceptions for clear, domain-specific errors.

Chain exceptions to preserve original context.

Leverage context managers for resource safety.

Follow best practices: catch narrowly, clean up, and log.

Debug effectively by reading tracebacks and using tools like pdb.

With these tools and patterns in your toolkit, you’ll be well-equipped to write
Python code that handles errors gracefully, remains maintainable, and lets
you recover or fail fast as appropriate.

You might also like