Opening a file with `with`
Variables disappear when a program ends; files do not. open(path, mode) gives you a file object, and mode says what you want: "r" to read (the default), "w" to write and "a" to append. Always open files with a with block: with open(path) as file:. When the block ends, Python closes the file for you, even if an error happened inside, so data is not lost or left half-written. Pass encoding="utf-8" so text is read and written the same way on every computer.
# Write a file, then read it back
with open("fills.txt", "w", encoding="utf-8") as file:
file.write("AAPL,184.25,200\n")
file.write("MSFT,410.20,50\n")
with open("fills.txt", encoding="utf-8") as file:
text = file.read()
print(repr(text)) # 'AAPL,184.25,200\nMSFT,410.20,50\n'Reading line by line
file.read() returns the whole file as one string. More often you loop over the file object, which gives one line at a time and works for files too big for memory: for line in file:. Each line still ends with \n, so clean it with line.strip(). A blank line becomes the empty string "" after stripping, which is false, so if text: skips it. file.readlines() and text.splitlines() give lists of lines when you want them all at once.
# Read line by line, skipping blank lines
with open("fills.txt", "a", encoding="utf-8") as file:
file.write("\n") # a blank line
total = 0.0
with open("fills.txt", encoding="utf-8") as file:
for line in file:
text = line.strip()
if not text:
continue
symbol, price, quantity = text.split(",")
total += float(price) * int(quantity)
print(round(total, 2)) # 57360.0Writing and appending
file.write(text) writes exactly the string you give it and returns the number of characters. It does not add a line break, so end each line with "\n" yourself. Mode "w" first empties the file (and creates it if it does not exist), so opening an existing file with "w" throws its old content away. Mode "a" keeps what is there and adds to the end. Only strings can be written: convert numbers first, for example with an f-string such as f"{price:.2f}".
# "w" starts over, "a" adds to the end
with open("log.txt", "w", encoding="utf-8") as file:
file.write("start\n")
with open("log.txt", "a", encoding="utf-8") as file:
file.write("order 1 filled\n")
file.write(f"pnl {12.5:+.2f}\n")
with open("log.txt", encoding="utf-8") as file:
print(file.read().splitlines()) # ['start', 'order 1 filled', 'pnl +12.50']
with open("log.txt", "w", encoding="utf-8") as file:
pass # opening with "w" emptied it
with open("log.txt", encoding="utf-8") as file:
print(repr(file.read())) # ''Paths and missing files
A relative path such as "fills.txt" is looked up in the program's current folder; use os.path.join(folder, name) to build paths without worrying about separators. Opening a file that does not exist for reading raises FileNotFoundError, which you can catch with try/except when a missing file is an expected case. For small files, pathlib.Path(path).read_text() and .write_text(text) do the open, read or write and close in one call.
import os
from pathlib import Path
# A missing file is an exception you can handle
def count_lines(path):
try:
with open(path, encoding="utf-8") as file:
return len(file.read().splitlines())
except FileNotFoundError:
return 0
print(count_lines("fills.txt")) # 3
print(count_lines("nope.txt")) # 0
# pathlib does open + read + close in one call
path = Path(os.path.join(".", "fills.txt"))
print(path.read_text(encoding="utf-8").splitlines()[0]) # AAPL,184.25,200"w" on the wrong path destroys data with no undo. Decide a simple format (one record per line, fields separated by commas) and write the reader and the writer together so they agree about it. Next you will meet the CSV format, which formalises exactly this idea.with open(path, mode, encoding="utf-8") as file:opens and always closes the file.for line in file:reads one line at a time;line.strip()removes the line break."w"empties the file,"a"appends;writeadds no line break.
Next up: CSV files, the standard way to store tables of prices and trades.
Lab · what's graded
- Load a watchlist from a file with
read_symbols25 pts - Turn a file of fills into tuples with
parse_trades25 pts - Save a profit and loss report with
write_report25 pts - Add to a log without losing it with
append_lines25 pts