
When you’re learning Python, you’re bound to run into errors. These come in two main types: syntax errors and exceptions.
Syntax Errors
Syntax errors, or parsing errors, happen when Python can’t understand your code. For example:
while True print('Hello world')
You’ll see something like this:
File "<stdin>", line 1
while True print('Hello world')
^^^^^
SyntaxError: invalid syntax
Here, Python highlights the spot where it got confused. It’s not always the actual mistake, but it helps narrow things down. In this case, the issue is a missing colon (:
) after while True
.
Exceptions
Even if your code is syntactically correct, it might still crash when something goes wrong during execution. These runtime errors are called exceptions.
Examples:
10 * (1 / 0)
# ZeroDivisionError: division by zero
4 + spam * 3
# NameError: name 'spam' is not defined
'2' + 2
# TypeError: can only concatenate str (not "int") to str
Each exception type describes what went wrong: dividing by zero, using an undefined name, or trying to mix strings and integers.
Handling Exceptions
You can write code to catch and handle exceptions gracefully using try
and except
. Here’s a basic example:
while True:
try:
number = int(input("Enter a number: "))
break
except ValueError:
print("Oops! That wasn't a valid number. Try again...")
How this works:
- The code inside
try
runs. - If it runs fine,
except
is skipped. - If an error occurs, Python jumps to the matching
except
block. - If no matching
except
is found, the program crashes.
You can have multiple except
blocks:
try:
# some risky code
except FileNotFoundError:
print("File not found!")
except ValueError:
print("Invalid value!")
except Exception as e:
print(f"Unexpected error: {e}")
raise
You can also catch multiple exceptions in a single block:
try:
# code
except (TypeError, NameError):
print("A type or name error occurred.")
Custom Exception Classes
You can define your own exception classes:
class MyError(Exception):
pass
raise MyError("Something went wrong!")
Exceptions can carry extra data, too:
try:
raise Exception("spam", "eggs")
except Exception as e:
print(type(e)) # <class 'Exception'>
print(e.args) # ('spam', 'eggs')
print(e) # ('spam', 'eggs')
x, y = e.args
print("x =", x)
print("y =", y)
Using else with try/except
You can run code if no exception occurs using else
:
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print("Cannot open file:", arg)
else:
print(arg, "has", len(f.readlines()), "lines")
f.close()
finally: Cleanup No Matter What
The finally
block is used for cleanup actions that must happen no matter what:
try:
raise KeyboardInterrupt
finally:
print("Goodbye, world!")
Even if an error happens or the user interrupts, the finally
block runs.
More realistic example:
def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
This will always print the finally
message, whether an error occurs or not.
Using with
for Automatic Cleanup
Instead of manually opening and closing files:
with open("myfile.txt") as f:
for line in f:
print(line, end="")
This way, the file is automatically closed, even if an error happens.
Raising Exceptions
You can raise exceptions yourself:
raise ValueError("Invalid input!")
To re-raise an exception after catching it:
try:
raise NameError("HiThere")
except NameError:
print("An exception flew by!")
raise
Exception Chaining
If one error leads to another, you can chain them:
try:
open("missing_file.txt")
except OSError as e:
raise RuntimeError("Unable to handle error") from e
To suppress the original exception info:
try:
open("missing_file.txt")
except OSError:
raise RuntimeError from None
Multiple Unrelated Exceptions (Python 3.11+)
If you want to raise multiple unrelated exceptions at once:
def f():
excs = [OSError("error 1"), SystemError("error 2")]
raise ExceptionGroup("Multiple errors occurred", excs)
You can handle specific ones using except*
:
try:
f()
except* OSError:
print("There were OSErrors")
except* SystemError:
print("There were SystemErrors")
This is useful for async code, tests, or batch processing where multiple things can fail independently.