Lesson 03 · foundations
The last stop before pandas.read_csv stops looking like magic.
Every dataset starts life as a file on disk — usually a .csv of raw text. Before pandas does the heavy lifting, you should know what it's doing underneath: opening a file, reading text, and splitting it into fields. That's this lesson.
A string indexes and slices exactly like a list — because it is a sequence, just an immutable one of characters.
ticker = "AAPL"
first = ticker[0] # "A"
last = ticker[-1] # "L"
sub = ticker[1:3] # "AP" (same start:stop rules as lists)
Common string methods you'll use constantly on real data:
row = " AAPL, 150.25, 1200000 "
row.strip() # "AAPL, 150.25, 1200000" — drop leading/trailing whitespace
row.strip().split(",") # ["AAPL", " 150.25", " 1200000"] — split into a list
"-".join(["A", "B"]) # "A-B" — the reverse of split
"aapl".upper() # "AAPL"
"AAPL".lower() # "aapl"
"AAPL".startswith("A") # True
.split(",") on a raw line is literally what a CSV parser does per row, before pandas or the csv module handle the edge cases (quoted commas, embedded newlines) for you.
with open(...)Files are opened with open() and should always be wrapped in a with block — it closes the file automatically, even if an error happens partway through.
with open("prices.csv") as f:
contents = f.read() # whole file as one string
# or, line by line (the common case):
with open("prices.csv") as f:
for line in f:
print(line.strip()) # strip() drops the trailing newline
with, not manual open/close
Without with, you'd need f = open(...) then remember f.close() — and forget it the moment an exception fires. with is Python's context manager pattern: it guarantees cleanup on the way out, no matter how the block exits.
csv module.split(",") breaks the moment a field contains a comma inside quotes (e.g. "Smith, John"). The standard library's csv module handles that correctly — use it instead of hand-rolled splitting for anything real:
import csv
with open("prices.csv") as f:
reader = csv.DictReader(f) # first row becomes field names automatically
for row in reader:
print(row["ticker"], row["price"])
# row is a dict: {"ticker": "AAPL", "price": "150.25", ...}
csv.DictReader gives you is a string — "150.25", not 150.25. You convert types yourself (float(row["price"])). This is exactly the "wrong types" cleanup step the mission calls out — pandas' read_csv does this type-guessing for you, which is why it exists.
Create a small CSV and parse it back out:
trades.csv with this content:
ticker,shares,price
AAPL,10,150.25
MSFT,5,310.00
GOOG,2,2800.50
csv.DictReader.shares and price to numbers and print the total value of that row (shares × price).import csv
total = 0
with open("trades.csv") as f:
reader = csv.DictReader(f)
for row in reader:
shares = int(row["shares"])
price = float(row["price"])
value = shares * price
print(f"{row['ticker']}: ${value:,.2f}")
total += value
print(f"Total: ${total:,.2f}")
pandas.read_csv automates. Next lesson: pandas itself, starting with loading this same CSV into a DataFrame in one line and seeing what it gives you for free.