Python · Lesson 12 of 15
Error Handling
try/except/finally and raising your own exceptions.
- Intermediate
- 13 min read
- 3 objectives
Before this lessonLesson 11: File Handling
What you will learn
- Catch specific exceptions
- Use finally for cleanup
- Raise ValueError with a message
Things go wrong: files are missing, users type letters where numbers belong, networks drop. When Python hits a problem it raises an exception. If nothing handles it, the program stops and prints a traceback. Error handling lets you respond gracefully instead.
Errors will happen, so plan for them
Users type letters where numbers are expected. Files go missing. Networks drop. A program that assumes everything goes right will crash the first time reality disagrees. Exception handling lets you say: "try this, and if a specific thing goes wrong, do this instead of crashing." It is the difference between a program that dies with a scary traceback and one that politely tells the user what to fix.
try and except
Put risky code in a try block and describe how to recover in except. Catch the specific exception you expect. A bare except: hides real bugs, including typos in your own code.
raw = "abc"
try:
n = int(raw)
except ValueError:
n = 0
print("not a number, using 0")
print(n)not a number, using 0 0
else and finally
else runs only when no exception happened, and finally always runs, which makes it the place for cleanup such as closing a connection.
try:
result = 10 / 2
except ZeroDivisionError:
print("cannot divide by zero")
else:
print("result:", result)
finally:
print("done")result: 5.0 done
Raising your own errors
Use raise to signal that the caller gave you bad input. Choose the most fitting built-in type (ValueError for a bad value, TypeError for a bad type) and write a message that says what was wrong.
def parse_port(text):
try:
port = int(text)
except ValueError:
raise ValueError(f"invalid port: {text}") from None
if not 1 <= port <= 65535:
raise ValueError("port out of range")
return port
print(parse_port("8080"))
print(parse_port("99999"))8080 ValueError: port out of range
Common exceptions
ValueError: right type, wrong value, likeint("x").TypeError: wrong type, like"a" + 1.KeyError/IndexError: missing dictionary key or list position.FileNotFoundError: the path does not exist.ZeroDivisionError: dividing by zero.
try, except, else, finally: what each part is for
def parse_age(text):
try:
age = int(text)
except ValueError:
print("not a number:", repr(text))
return None
else:
print("parsed fine")
return age
finally:
print("(always runs)")
print(parse_age("42"))
print(parse_age("forty"))parsed fine (always runs) 42 not a number: 'forty' (always runs) None
try: the risky code.except ValueError: runs only if that error happens. Be specific.else: runs only when nothing went wrong.finally: always runs, good for cleanup such as closing connections.
Catch specific errors, not everything
Writing a bare except: hides real bugs, including typos. Catch the exact exception you expect, and let unexpected ones crash loudly so you notice them.
data = {"price": "12.5"}
try:
value = float(data["price"]) / int(data.get("qty", 0))
except (KeyError, ValueError):
print("bad input")
except ZeroDivisionError:
print("quantity was zero")quantity was zero
Writing helpful error messages
Use raise when a caller gives you something invalid. A clear message saves the next developer (often you) hours of guessing.
def set_age(age):
if not 0 <= age <= 130:
raise ValueError(f"age out of range: {age}")
return age
try:
set_age(200)
except ValueError as err:
print("Rejected:", err)Rejected: age out of range: 200
Worked example: ask until valid
A very common pattern: keep asking until the input is acceptable. Here the inputs are simulated with a list so you can run it.
answers = iter(["abc", "-5", "27"])
while True:
text = next(answers)
try:
age = int(text)
if age < 0:
raise ValueError("negative")
except ValueError:
print(f"{text!r} is not valid, try again")
continue
print("Accepted", age)
break'abc' is not valid, try again '-5' is not valid, try again Accepted 27
Key takeaways
- Wrap risky code in
try; handle expected problems inexcept. - Catch specific exceptions; never hide bugs with a bare
except:. elseruns on success,finallyalways runs.raiseyour own errors with clear messages.
# Write your solution here
