When writing Python programs, errors are inevitable. Whether you’re reading a file, parsing user input, or making network requests, things can (and will) go wrong at runtime. If not handled properly, these failures can crash your application and frustrate users.
That’s where exception handling in Python comes in. By mastering try/except
, else
, finally
, and context managers (with
), you can write resilient code that handles errors gracefully while still surfacing real bugs when they occur.
In this guide, we’ll walk through the best practices for handling exceptions in Python, complete with code examples, so you can keep your programs reliable, readable, and production-ready.
Core Principles of Exception Handling in Python
Before diving into methods, keep these golden rules in mind:
- Catch only specific exceptions you expect (
ValueError
,FileNotFoundError
) instead of using blanket handlers. - Use
else
for success paths andfinally
for guaranteed cleanup. - Favor context managers (
with
) for files and resources. - Never silently swallow bugs — log and re-raise them instead.
- Reserve catch-all handlers for top-level boundaries where you need to log or fail fast.
Method 1 — Catch Specific Exceptions (Recommended)
Instead of handling every possible error, catch the exact ones you expect:
raw = input("Select a fruit number (0-2): ")
try:
selection = ["apple", "pear", "banana"][int(raw)]
print("You chose:", selection)
except ValueError:
print("Not a number.")
except IndexError:
print("Choice out of range.")
You can also group exceptions when recovery is the same:
try:
selection = ["apple", "pear", "banana"][int(raw)]
except (ValueError, IndexError) as e:
print("Invalid selection:", type(e).__name__)
Common exceptions to know:
OSError
family → File handlingValueError
/TypeError
→ Data issuesZeroDivisionError
→ Math errorsKeyError
/IndexError
→ Collections
Method 2 — Use else
and finally
for Clean Separation
else
runs only if no error occurs, while finally
always runs for cleanup.
try:
f = open("config.json", "r", encoding="utf-8")
except FileNotFoundError:
print("No config file found.")
else:
data = f.read()
print("Loaded", len(data), "bytes.")
f.close()
With finally
:
f = None
try:
f = open("config.json", "r", encoding="utf-8")
data = f.read()
except OSError as err:
print("OS error:", err)
finally:
if f:
f.close()
Method 3 — Guard the Program Entry Point
Wrap your main workflow with a top-level exception handler to log and fail fast.
import logging, sys
logging.basicConfig(level=logging.INFO)
def main():
# core workflow
return 0
if __name__ == "__main__":
try:
code = main()
except Exception:
logging.exception("Unhandled error")
sys.exit(1)
sys.exit(code)
Returning a non-zero exit code signals automation tools that the run failed.
Method 4 — Use Context Managers (with
) for Resources
Context managers automatically clean up files, sockets, and other resources.
from pathlib import Path
try:
with Path("data.txt").open("r", encoding="utf-8") as f:
print(f.readline().strip())
except FileNotFoundError:
print("Create data.txt first.")
Keep only risky operations inside the try
block:
try:
with open("image.png", "rb") as fh:
blob = fh.read()
except OSError as e:
print("File access failed:", e)
# process blob outside the block
Method 5 — Raise, Re-Raise, and Chain Exceptions
Raise when conditions fail:
def parse_age(s: str) -> int:
if not s.isdigit():
raise ValueError("Age must contain only digits")
age = int(s)
if age < 0:
raise ValueError("Age cannot be negative")
return age
Re-raise after logging:
import logging
try:
do_risky_thing()
except OSError as err:
logging.error("OS error: %s", err)
raise
Chain exceptions with context:
from pathlib import Path
import json
def load_json(path: str):
try:
text = Path(path).read_text(encoding="utf-8")
except OSError as e:
raise RuntimeError(f"Failed to read {path}") from e
return json.loads(text)
Method 6 — Catch-All Handling (Use Sparingly)
Sometimes you need a broad safety net:
import traceback
try:
risky()
except Exception as e:
print(f"Unexpected {type(e).__name__}: {e}")
traceback.print_exc()
Avoid catching BaseException
unless you’re handling shutdown signals:
try:
service_loop()
except BaseException as e:
print(f"Caught {type(e).__name__}; shutting down cleanly.")
raise
Method 7 — Handle Multiple Errors with ExceptionGroup (Python 3.11+)
Aggregate multiple failures with ExceptionGroup
:
def run_tests(tests):
errors = []
for t in tests:
try:
t.run()
except Exception as e:
e.add_note(f"Test {t.name} failed")
errors.append(e)
if errors:
raise ExceptionGroup("Batch failures", errors)
Handle them selectively with except*
:
try:
run_tests(tests)
except* (ValueError, TypeError):
print("Some data errors occurred.")
except* OSError:
print("Some OS errors occurred.")
Quick Troubleshooting Patterns
- Input parsing → wrap
int()
orfloat()
withexcept ValueError
- File I/O → catch
FileNotFoundError
,PermissionError
, orOSError
- Networking/API calls → handle timeouts, retries, and connection errors
- Always log exceptions → use
logging.exception()
ortraceback.print_exc()
Conclusion
Exception handling in Python isn’t just about preventing crashes — it’s about writing clean, maintainable, and fault-tolerant code. By catching specific errors, using else
and finally
wisely, leveraging context managers, and applying catch-all strategies only when appropriate, you can create applications that are both robust and easy to debug.
Master these techniques, and you’ll be equipped to handle anything Python throws your way — from simple input mistakes to complex multi-error workflows.
And if you'd like to go a step further in supporting us, you can treat us to a virtual coffee ☕️. Thank you for your support ❤️!

We do not support or promote any form of piracy, copyright infringement, or illegal use of software, video content, or digital resources.
Any mention of third-party sites, tools, or platforms is purely for informational purposes. It is the responsibility of each reader to comply with the laws in their country, as well as the terms of use of the services mentioned.
We strongly encourage the use of legal, open-source, or official solutions in a responsible manner.
Comments