Even the best code encounters unexpected situations—networks drop, files go missing, and users input literal garbage. In Python, an unhandled error instantly crashes your entire application. Exception handling is the art of surviving those catastrophic moments gracefully.
1The Try-Except Block
When Python encounters an impossible operation—like dividing by zero—it triggers a fatal runtime error and immediately terminates execution. In production, this means your AI pipeline stops processing data, and your users stare at a frozen loading screen.
We defend against this using the try-except block. You place dangerous code inside the try block. If the code executes successfully, Python skips the except block entirely. But if the code fails, instead of crashing the program, Python instantly intercepts the error, silences the crash, and executes the fallback logic inside the except block.
try:
# The dangerous operation
result = 10 / 0
print(result)
except ZeroDivisionError:
# The rescue block
print("Oops! Cannot divide by zero.")
print("The script survives and continues running.")The script survives and continues running.
2Else and Finally
Professional error handling goes beyond just catching crashes. Python provides two advanced clauses: else and finally.
The else block executes *only* if the try block succeeds without throwing any exceptions. This keeps your try block focused solely on the dangerous operation, separating the success logic. The finally block is guaranteed to execute no matter what happens—even if the script succeeds, fails, or encounters an entirely unhandled error. We use finally for mandatory cleanup tasks, like securely closing database connections or freeing up GPU memory.
try:
file = open('model_weights.pt', 'r')
except FileNotFoundError:
print("Error: File missing!")
else:
print("Success: Weights loaded.")
finally:
print("Cleanup: Closing file handlers.")Cleanup: Closing file handlers.
3Raising Manual Exceptions
Sometimes the Python compiler thinks the code is perfectly fine, but your business logic dictates that a state is illegal. For example, multiplying a matrix by a negative age won't crash Python mathematically, but it will ruin your AI model.
In these scenarios, you act as the compiler. You use the raise keyword to intentionally trigger an exception and halt the execution pipeline. This immediately alerts the calling function that something is fundamentally wrong, preventing silent logic bugs from propagating deep into your application.
def set_age(age):
# Python math allows negatives, but our logic doesn't.
if age < 0:
# We manually blow up the script.
raise ValueError("Age cannot be negative")
return age
# This triggers the manual crash.
set_age(-5)File "main.py", line 7, in <module>
set_age(-5)
File "main.py", line 4, in set_age
raise ValueError("Age cannot be negative")
ValueError: Age cannot be negative
