Python Error Handling
Making Your Programs Robust: Understanding Errors and Exceptions
In Python, errors can happen for many reasons—maybe a file doesn't exist, a user enters the wrong input, or you try to divide by zero. If you don't handle these errors, your program will crash. Exception handling lets you deal with errors gracefully, so your program can keep running or fail in a controlled way.
Syntax Errors vs. Exceptions
There are two main types of errors in Python:
- Syntax errors: These happen when Python can't understand your code at all. For example, if you forget a colon or a parenthesis:
# SyntaxError: invalid syntax
if True
print("Hello!")
- Exceptions: These happen while your program is running, even if the code is written correctly. For example, dividing by zero or trying to open a file that doesn't exist:
# ZeroDivisionError
result = 10 / 0
# FileNotFoundError
with open("missing.txt") as f:
data = f.read()
The Basics: try and except
To handle exceptions, use a try
block. You put the code that might cause an error inside try
, and then use except
to catch and handle the error.
try:
number = int(input("Enter a number: "))
print(10 / number)
except ZeroDivisionError:
print("You can't divide by zero!")
except ValueError:
print("That's not a valid number!")
- If the user enters 0, it prints the message for
ZeroDivisionError
. - If the user enters something that's not a number, it prints the message for
ValueError
.
Catching Specific Exceptions
You can catch specific types of exceptions by naming them in the except
block. This lets you handle different errors in different ways.
try:
value = int(input("Enter a number: "))
except ValueError:
print("Please enter a valid integer.")
If you want to catch any exception (not recommended for most cases), you can use a plain except:
block. But it's better to be specific so you don't hide bugs.
Multiple except Blocks
You can have several except
blocks to handle different types of errors:
try:
with open("data.txt") as f:
content = f.read()
number = int(content)
print(100 / number)
except FileNotFoundError:
print("File not found.")
except ValueError:
print("File does not contain a valid number.")
except ZeroDivisionError:
print("Number in file is zero!")
You can also catch multiple exceptions in one block:
try:
risky()
except (TypeError, ValueError):
print("A type or value error occurred.")
The else Block
You can add an else
block after all the except
blocks. The code in else
runs only if no exception was raised in the try
block.
try:
n = int(input("Enter a number: "))
except ValueError:
print("Not a number!")
else:
print(f"You entered {n}")
The finally Block
A finally
block will always run, whether or not an exception occurred. It's useful for cleanup actions, like closing files or releasing resources.
try:
f = open("data.txt")
# Do something with the file
except FileNotFoundError:
print("File not found.")
finally:
print("This runs no matter what.")
if 'f' in locals() and not f.closed:
f.close()
Raising Exceptions
You can raise exceptions yourself using the raise
statement. This is useful if you want to signal that something went wrong in your own code.
def divide(a: float, b: float) -> float:
if b == 0:
raise ZeroDivisionError("Cannot divide by zero!")
return a / b
print(divide(10, 2)) # Output: 5.0
# print(divide(10, 0)) # Raises ZeroDivisionError
Common Built-in Exceptions
Here are some exceptions you might see often:
ValueError
: Raised when a function gets an argument of the right type but an inappropriate value.TypeError
: Raised when an operation is applied to an object of the wrong type.ZeroDivisionError
: Raised when you divide by zero.FileNotFoundError
: Raised when a file or directory is requested but doesn't exist.IndexError
: Raised when a sequence subscript is out of range.KeyError
: Raised when a dictionary key isn't found.NameError
: Raised when a variable is not defined.
User-Defined Exceptions
You can create your own exception types by defining a new class that inherits from Exception
.
class MyCustomError(Exception):
pass
def do_something(value: int) -> None:
if value < 0:
raise MyCustomError("Negative value not allowed!")
print(f"Value is {value}")
do_something(5) # Output: Value is 5
# do_something(-1) # Raises MyCustomError
Summary
- Syntax errors stop your code from running at all; exceptions happen while your code is running.
- Use
try
andexcept
to handle exceptions and keep your program running. - Catch specific exceptions to handle different errors in different ways.
- Use
else
for code that should run only if no error occurred. - Use
finally
for cleanup that should always happen. - You can raise exceptions yourself with
raise
. - You can define your own exception types by subclassing
Exception
.