A Wandering Mind · Computer Science
PYTHON GUIDE

Learn · Run · Break · Fix

A learning series from A Wandering Mind

Eighteen interlinked lessons on strings, lists, files, exceptions, and dictionaries—with original explanations, runnable examples, real output, and supporting CPSC 1301K lectures.

course.py
>>> guide = {
...   "lessons": 18,
...   "modules": 5,
...   "python": "3.10+"
... }
>>> guide["goal"] = "understand it"
Module 3 · Files · Lesson 13 of 18

Reading Files and Processing Lines in Python

Once a text file is open, Python gives you several ways to move its contents into your program. read() retrieves a larger block, readline() retrieves one line at a time, readlines() builds a list of lines, and the file object itself can be used directly in a for loop. This lesson compares those approaches and shows how newline characters and the file’s current position affect what you receive.

Prerequisite: Complete Verifying a File Opened, and Closing It Properly. All examples here use the preferred with open(...) context-manager pattern.

read() retrieves text from the current file position

The simplest reading method is read(). With no argument, it returns the remaining contents of a text file as one Python string. If the file contains line breaks, those newline characters become part of that string.

For a small configuration file, short note, or tiny practice file, reading everything at once can be convenient. For very large files, however, loading the entire remaining file into memory may be unnecessary. That is one reason Python also supports line-based reading and direct iteration.

Example 1 · Read the entire text fileVerified
with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()
print(content)
alpha
beta
gamma

The variable content is a string, not a list. The three source lines remain separated because the string includes the file’s newline characters. If you need to treat individual lines as separate values, one of the next approaches may be more convenient.

Reading advances the file position. A file object keeps track of where the next read will begin. After read() reaches the end, another ordinary read() on the same open object returns an empty string unless you reposition or reopen the file.

readline() retrieves one line at a time

readline() returns the next line from the file and advances the file position to the line that follows it. This gives you explicit control when you only want one or a few lines rather than the entire file.

The returned string usually includes its trailing newline character. Calling strip() removes leading and trailing whitespace, including that newline. Use it deliberately: if spaces at the beginning or end of a line are meaningful data, removing all surrounding whitespace may be too aggressive.

Example 2 · Read two lines separatelyVerified
with open("notes.txt", "r", encoding="utf-8") as file:
    first = file.readline().strip()
    second = file.readline().strip()
print(first)
print(second)
alpha
beta

The first call consumes the first line. The second call begins where the first one stopped. That stateful behavior is important: reading methods do not normally restart at the beginning every time they are called.

readlines() returns a list of line strings

If your next step specifically benefits from list operations, readlines() can retrieve the remaining lines into a list. Each list element is one line string, and the newline characters are normally retained.

This connects file I/O directly back to Module 2. Once the lines are in a list, you can use indexing, slicing, membership tests, list methods, or loops. The tradeoff is memory: readlines() builds the collection in memory all at once.

Example 3 · Read file lines into a listVerified
with open("notes.txt", "r", encoding="utf-8") as file:
    lines = file.readlines()
print(lines)
print(len(lines))
['alpha\n', 'beta\n', 'gamma\n']
3

The representation makes the \n characters visible because the entire list is printed at once. Those characters were already in the file; readlines() did not invent extra lines. The final output confirms that the returned list contains three elements.

Direct iteration is often the cleanest line-by-line pattern

A text file object is iterable, so you can write for line in file: without first calling readlines(). Python then supplies one line at a time. This is often the clearest choice when your goal is to process each line once and you do not need the entire list of lines afterward.

Direct iteration also avoids creating a separate list containing all lines. That can matter when files are large. The pattern combines naturally with the list-loop skills from Lesson 10.

Example 4 · Process each line as it is readVerified
with open("scores.txt", "r", encoding="utf-8") as file:
    for line in file:
        score = int(line.strip())
        print(score + 1)
89
92
77

Each source line begins as a string. strip() removes the newline, int() converts the remaining text into an integer, and the program performs arithmetic on that converted value. File input frequently requires this kind of parsing because text files store characters, not pre-typed Python integers or floats.

Whole remainderfile.read()

Returns the remaining text as one string.

One linefile.readline()

Returns the next line string and advances the file position.

List of linesfile.readlines()

Returns the remaining lines as a Python list.

Stream line by linefor line in file:

Processes one line at a time without first building a list of all lines.

Choose the reading pattern that matches the job

There is no single “best” reading method for every file. Use read() when you genuinely want one string containing the remaining text. Use readline() when a small number of specific lines should be consumed in sequence. Use readlines() when having all remaining lines as a list is useful. Use direct iteration when you want to process lines one at a time.

For large text files, direct iteration is usually a strong default because it avoids loading the entire file into a separate collection. For small teaching examples, all four patterns are reasonable as long as you understand what type each one returns and how it advances the file position.

Common mistakes while reading files

The following failures were executed in Python. They demonstrate that successful open() does not guarantee every later read is valid: mode, argument types, and text encoding still matter.

Mistake 1 · Reading from a write-only file
with open("output.txt", "w", encoding="utf-8") as file:
    print(file.read())
Traceback (most recent call last):
  File "/tmp/ipykernel_313/964632975.py", line 30, in run_err
    exec(compile(code, str(work / filename), "exec"), {})
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/awm_lesson13/mistake1_not_readable.py", line 2, in <module>
io.UnsupportedOperation: not readable

The file object is open, but its mode does not permit reading. Resource state and access mode are separate questions.

Mistake 2 · Passing a string as the read size
with open("notes.txt", "r", encoding="utf-8") as file:
    print(file.read("2"))
Traceback (most recent call last):
  File "/tmp/ipykernel_313/964632975.py", line 30, in run_err
    exec(compile(code, str(work / filename), "exec"), {})
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/awm_lesson13/mistake2_read_string_size.py", line 2, in <module>
TypeError: argument should be integer or None, not 'str'

The optional size argument is numeric. The string "2" is text, so Python will not silently convert it into the integer 2.

Mistake 3 · Passing text as the readlines() size hint
with open("notes.txt", "r", encoding="utf-8") as file:
    print(file.readlines("2"))
Traceback (most recent call last):
  File "/tmp/ipykernel_313/964632975.py", line 30, in run_err
    exec(compile(code, str(work / filename), "exec"), {})
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/awm_lesson13/mistake3_readlines_string_hint.py", line 2, in <module>
TypeError: argument should be integer or None, not 'str'

readlines() also accepts an optional numeric size hint, not a string. Most beginner code can simply omit this argument.

Mistake 4 · Decoding non-UTF-8 bytes as UTF-8 text
with open("bad-utf8.bin", "r", encoding="utf-8") as file:
    print(file.read())
Traceback (most recent call last):
  File "/tmp/ipykernel_313/964632975.py", line 30, in run_err
    exec(compile(code, str(work / filename), "exec"), {})
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/awm_lesson13/mistake4_bad_encoding.py", line 2, in <module>
  File "<frozen codecs>", line 325, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

Text mode must decode bytes into Unicode characters. If the file’s bytes are not valid for the chosen encoding, Python raises UnicodeDecodeError. The fix is to know the file’s real encoding—or, if the data is not text at all, open it in the appropriate binary mode instead.

Supporting classroom explanations

This page is original A Wandering Mind instructional material. The two CPSC 1301K lectures below reinforce Python’s reading methods and the natural connection between file objects and loops.

Reading From a File — by Hyrum Carroll · 13:11. Watch on YouTube ↗ · CPSC 1301K playlist ↗

What it adds: a longer classroom walkthrough of retrieving text from an open file and working with the values returned by file-reading operations.

Loops and Files — by Hyrum Carroll · 8:45. Watch on YouTube ↗ · CPSC 1301K playlist ↗

What it adds: a focused explanation of iterating through file contents one line at a time with a loop.

Try it yourself

Use small text fixtures while practicing. Before running the answer, decide whether the result should be a string, a list, or a converted number.

Exercise 1 · Read all notes

Open notes.txt with a context manager, read the whole file into one string, then print it without an extra blank line at the end.

Show one answer
with open("notes.txt", "r", encoding="utf-8") as file:
    text = file.read()
print(text.strip())
alpha
beta
gamma

Exercise 2 · Read only the first line

Open notes.txt, retrieve one line with readline(), remove its trailing newline, and print it.

Show one answer
with open("notes.txt", "r", encoding="utf-8") as file:
    first = file.readline().strip()
print(first)
alpha

Exercise 3 · Sum numeric lines

Assume scores.txt contains 88, 91, and 76 on separate lines. Loop over the file, convert each stripped line to an integer, add the values, and print the total.

Show one answer
with open("scores.txt", "r", encoding="utf-8") as file:
    total = 0
    for line in file:
        total += int(line.strip())
print(total)
255

What you should carry into Lesson 14

You now know four practical ways to consume text from a file. read() returns one string, readline() advances one line at a time, readlines() returns a list of line strings, and direct iteration processes lines without first building that list. In every case, reading advances the file’s current position.

The final Files lesson reverses the direction of data flow. Continue to Writing and Appending to Files to learn how write(), writelines(), write mode, and append mode place program output onto disk.