hayaliv / Hi! Python / Level 1
Text and the `with` statement
Read text one line at a time, and let with close the file for you.
Think of it like this
Reading a text file is like reading a letter one line at a time. A with block is like borrowing a book from a library desk: when you walk away from the desk, the book goes back on the shelf.
Where the analogy stops being true. A library book is returned by you or a librarian, but with closes the file by itself, even if an error happens inside the block.
What to know
- Looping over a file object gives you one line per step.
- Each line keeps its newline character at the end (see predict item 1), so use
rstrip("\n")when you want only the text. io.StringIOis an in-memory text stream, so we can practise file-style code without touching the disk.- The docs call
withgood practice for file objects: the file is closed after its suite finishes, even if an exception is raised. - The real-file pattern is
with open(path, encoding="utf-8") as f:. We only show it here, we do not run it. - Pass
encodingyourself. In Python 3.12 the default is platform dependent, so naming the encoding yourself is a good habit.
Example
import io
raw = "I can meet Tuesday.\nNot interested, thanks.\n\nCall me at 5pm.\n"
with io.StringIO(raw) as f:
for number, line in enumerate(f, start=1):
text = line.rstrip("\n")
print(number, repr(text))
print(f.closed)
It prints:
1 'I can meet Tuesday.'
2 'Not interested, thanks.'
3 ''
4 'Call me at 5pm.'
True
Predict, then check
1. What does this print?
import io
print(list(io.StringIO("a\nb\n")))Show the answer
['a\n', 'b\n']Looping over the stream gives lines, and each line still ends with a newline character.
2. What does this print?
import io
f = io.StringIO("one\ntwo\n")
first = f.readline()
rest = list(f)
print(repr(first), rest)Show the answer
'one\n' ['two\n']The loop carries on from where readline stopped, so only the second line is left.
3. What does this print?
import io
with io.StringIO("hi") as f:
data = f.read()
try:
f.read()
except ValueError:
print("closed", data)Show the answer
closed hiAfter the with block the stream is closed, so reading again raises ValueError.
Try it
Write count_nonblank_lines(f). It receives a file-like object and returns how many lines contain something other than whitespace.
def count_nonblank_lines(f):
return 0
Show a solution
def count_nonblank_lines(f):
return sum(1 for line in f if line.strip())Common mistake
A line read from a file still ends with a newline, so comparing it to a plain label such as "yes" is False until you strip it (see predict item 1).
In a small-language-model project
In a fine-tuning project you often start with a plain text file of raw replies, one per line. Reading it with with and an explicit encoding, then skipping blank lines, is the first cleaning step. Replies in Albanian, or any language with letters outside ASCII such as ë and ç, are a good reason to name the encoding yourself.
Sources
Each quote below appears word for word on the cited page of the official Python documentation (version 3.12).
For reading lines from a file, you can loop over the file object.
docs.python.org/3.12/tutorial/inputoutput.html — Looping over a file object reads it line by line.It is good practice to use the with keyword when dealing with file objects.
docs.python.org/3.12/tutorial/inputoutput.html — The docs call `with` good practice for file objects.The advantage is that the file is properly closed after its suite finishes, even if an exception is raised at some point.
docs.python.org/3.12/tutorial/inputoutput.html — `with` closes the file even if an exception occurs.Finally, StringIO is an in-memory stream for text.
docs.python.org/3.12/library/io.html — StringIO is an in-memory text stream.The default encoding is platform dependent (whatever locale.getencoding() returns)
docs.python.org/3.12/library/functions.html — The default encoding of open() is platform dependent.Return a copy of the string with trailing characters removed.
docs.python.org/3.12/library/stdtypes.html — rstrip returns a copy with trailing characters removed.