Files
14 min
open(path, mode) gives you a file object; the most common modes are
"r" (read, the default), "w" (write — creates or overwrites), and
"a" (append). Always use it with with, which guarantees the file gets
closed automatically when the block ends:
with open("notes.txt", "w") as f:
f.write("hello\n")
with open("notes.txt") as f:
contents = f.read()
print(contents) # hello
Iterating a file object directly (for line in f) reads it one line at a time — the standard way to process a file without loading it all into memory at once.
Without with, a crash between open() and close() leaves the file
handle open — usually harmless for a script that exits immediately after,
but a real bug in a long-running program (you eventually run out of file
handles) or if you needed the write to be flushed to disk before some
other code reads it. with guarantees the close happens, exception or
not — the same "guaranteed cleanup" pattern you get from a finally
block, but scoped automatically to the object.
# risky — if something raises between open and close, the file stays open
f = open("data.txt", "w")
f.write("...")
f.close()
# safe — closes automatically, even on an exception
with open("data.txt", "w") as f:
f.write("...")
Write a function `write_and_read(path, text)` that writes `text` to the file at `path` (mode 'w'), then reads it back and returns the contents. Use `with open(...)` for both.
Write a function `append_lines(path, lines)` that writes each string in `lines` to the file at `path`, one per line (each followed by a newline), then reads the whole file back and returns it as one string.
Why is `with open(path) as f: ...` preferred over calling `open()` and `f.close()` manually?
You can read and write files using with open(...), and know why the context-manager form is preferred over manual open/close.