Files, Errors and Modules
Exceptions
try:
value = int(text)
except ValueError:
value = 0
except (TypeError, KeyError) as exc:
print(exc)
else:
print("nothing was raised")
finally:
cleanup() # always runs
Name what you expect. A bare except: also swallows your own typos and
KeyboardInterrupt.
The ones you will meet
| Exception | Cause |
|---|---|
ValueError | right type, wrong value — int("abc") |
TypeError | wrong type — "a" + 1 |
KeyError | missing dictionary key |
IndexError | list index out of range |
AttributeError | no such attribute, often on None |
ZeroDivisionError | dividing by zero |
FileNotFoundError | opening something absent |
AssertionError | a failed assert |
Raising
raise ValueError("amount must be positive")
class InsufficientFunds(Exception):
pass
raise InsufficientFunds("not enough")
Return values can be ignored by accident; exceptions cannot.
assert vs raise
| Use for | Note | |
|---|---|---|
assert | programmer mistakes | removed when Python runs with -O |
raise | bad input from outside | always present |
Never validate user input with assert.
Reading a traceback
Traceback (most recent call last):
File "shop.py", line 22, in <module>
print(total_price(basket))
File "shop.py", line 15, in total_price
return sum(item["price"] for item in items)
KeyError: 'price'
- Read the last line — that is the actual error.
- Find the last frame in your own code.
- The line number is where it surfaced, not always where it started.
Imports
import math # math.sqrt(16)
from math import sqrt, pi # sqrt(16)
import statistics as stats # stats.mean(...)
Avoid from module import * — it hides where names came from and causes collisions.
Standard library
math
sqrt, floor, ceil, pi, inf, isclose(a, b)
random
random.seed(42) # makes runs repeatable — essential for testing
random.randint(1, 6) # inclusive at BOTH ends
random.choice(seq)
random.shuffle(list) # in place
random.sample(seq, k) # k distinct items
datetime
from datetime import date, datetime, timedelta
today = date.today()
launch = date(2026, 1, 15)
launch + timedelta(days=30)
(today - launch).days
today.isoformat() # "2026-01-15"
datetime.now().strftime("%Y-%m-%d %H:%M")
collections
from collections import Counter, defaultdict
Counter("mississippi").most_common(2) # [('i', 4), ('s', 4)]
totals = defaultdict(int)
totals["a"] += 1 # no need to check whether the key exists
groups = defaultdict(list)
groups["x"].append(1)
JSON
import json
json.dumps(data) # object → string
json.loads(text) # string → object
json.dump(data, file) # object → file
json.load(file) # file → object
json.dumps(data, indent=2, sort_keys=True)
json.dumps(data, separators=(",", ":")) # compact
The s means string. Malformed input raises JSONDecodeError, a subclass of
ValueError.
| JSON | Python |
|---|---|
null | None |
true / false | True / False |
| array | list (tuples become lists) |
| object | dict (keys are always strings) |
Files
with open("notes.txt", "w") as f: # "w" TRUNCATES first
f.write("first line\n")
with open("notes.txt", "a") as f: # append
f.write("second\n")
with open("notes.txt") as f: # "r" is the default
whole = f.read()
with open("notes.txt") as f:
for line in f: # one at a time — works on huge files
print(line.rstrip("\n"))
| Mode | Meaning |
|---|---|
"r" | read (default) |
"w" | write, truncating what is there |
"a" | append |
"x" | create, failing if it exists |
Always use with — it closes the file even when something raises.
A safe reading pattern
def count_lines(path):
try:
with open(path) as f:
return sum(1 for line in f if line.strip())
except FileNotFoundError:
return 0