Week 9: File Operations & Context Managers

4443 words
22 min read
2026-09-12T00:00:00.000Z
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

Opening files with context managers (with open), reading modes, line-by-line streaming, writing, and encoding. # Programming in Python — Week 9: File Operations & Context Managers The official IITM syllabus lists **Week 9: File Operations**.

Programming in Python — Week 9: File Operations & Context Managers

The official IITM syllabus lists Week 9: File Operations. Since the syllabus file only provides the week heading, the detailed material below is a standard Python file-handling expansion, not a claim about the exact lecture ordering.

TL;DR

Until now, most data lived inside the running program:
python
marks = [80, 90, 75]
When the program ends, that in-memory state disappears.
Files let programs work with persistent data:
text
disk file
   ↓
read
   ↓
Python program
   ↓
process
   ↓
write
   ↓
disk file
Core Week 9 ideas:
  • opening files
  • reading
  • writing
  • appending
  • file modes
  • closing files
  • with open(...)
  • reading line-by-line
  • stripping newline characters
  • splitting/parsing text
  • converting text to numbers
  • processing structured text
  • handling paths and missing files conceptually
The central pattern is:
open→read/write→close\boxed{ \text{open} \rightarrow \text{read/write} \rightarrow \text{close} }

1. What is a file?

A file is persistent data stored outside the program's temporary memory.
Examples:
text
marks.txt
students.csv
notes.md
config.txt
Unlike a Python variable, a file normally continues to exist after the program terminates.

2. Why files matter

Suppose your program calculates:
python
total = 420
If the program exits, total disappears from memory.
If you save it:
text
result.txt
another program—or the same program later—can read it again.

3. Basic file workflow

A file operation usually follows:
text
1. Open file
2. Perform operation
3. Close file
Example:
python
f = open("data.txt", "r")
content = f.read()
f.close()

4. open()

Python's basic file-opening function is:
python
open(filename, mode)
Example:
python
f = open("data.txt", "r")
This returns a file object referenced by:
python
f

5. File modes

Important modes include:
ModeMeaning
"r"read
"w"write, replacing existing contents
"a"append to end
"x"create a new file, fail if it exists
For basic Week 9 work, "r", "w", and "a" matter most.

6. Read mode

python
f = open("data.txt", "r")
means:
open an existing file for reading.
If the file does not exist, opening usually raises an error.

7. .read()

python
content = f.read()
reads the remaining file contents as a string.
Suppose data.txt contains:
text
hello
world
Then:
python
content = f.read()
conceptually gives:
python
"hello\nworld\n"
depending on the file's exact final newline.

8. Newline character

Text files use newline characters to separate lines.
Python commonly represents newline as:
python
"\n"
So:
python
"hello\nworld"
represents:
text
hello
world

9. .readline()

python
line = f.readline()
reads one line at a time.
Suppose:
text
A
B
C
Then successive calls conceptually return:
python
"A\n"
"B\n"
"C\n"

10. .readlines()

python
lines = f.readlines()
returns a list of lines.
Example:
python
["A\n", "B\n", "C\n"]
The newline characters may remain attached.

11. File iteration

A common and clean pattern is:
python
for line in f:
    print(line)
The file object itself can be iterated line-by-line.
This avoids loading the entire file into one string first.

12. Why line-by-line processing matters

For a tiny file, this:
python
content = f.read()
is fine.
For a very large file, reading line-by-line can be more memory-efficient:
python
for line in f:
    process(line)
Only a small portion needs to be handled at a time.

13. .strip()

Because lines often end with:
python
"\n"
a common pattern is:
python
line = line.strip()
Example:
python
"hello\n".strip()
becomes:
python
"hello"

14. .strip() removes more than newline

It removes leading/trailing whitespace in general.
Example:
python
"   hello \n".strip()
becomes:
python
"hello"
If spaces are meaningful data, use stripping carefully.

15. Basic read example

File:
text
10
20
30
Program:
python
f = open("numbers.txt", "r")

for line in f:
    line = line.strip()
    print(line)

f.close()
Output:
text
10
20
30

16. File text is still text

Even if a line contains:
text
25
reading it gives something like:
python
"25\n"
not integer:
python
25
So numerical processing needs conversion.

17. Convert lines to integers

python
f = open("numbers.txt", "r")

total = 0

for line in f:
    x = int(line.strip())
    total += x

f.close()

print(total)
If file contains:
text
10
20
30
result:
60.60.

18. Same accumulator patterns still apply

File input changes where data comes from.
The algorithm remains familiar:
python
total = 0

for line in f:
    x = int(line)
    total += x
This is the same running-sum pattern used for lists and user input.

19. with open(...)

Preferred Python pattern:
python
with open("data.txt", "r") as f:
    content = f.read()
After the block ends, Python handles closing the file automatically.

20. Why with is useful

Instead of:
python
f = open("data.txt", "r")
...
f.close()
use:
python
with open("data.txt", "r") as f:
    ...
It reduces the risk of forgetting to close the file.

21. Scope of the with block

python
with open("data.txt", "r") as f:
    content = f.read()

print(content)
The file operation happens inside the block.
After leaving it, the file is closed.
The variable content can still be used.

22. Write mode

python
with open("output.txt", "w") as f:
    f.write("hello")
This writes:
text
hello
to the file.

23. "w" can overwrite

This is critical.
If output.txt already contains:
text
OLD DATA
and you open:
python
open("output.txt", "w")
the previous contents are normally truncated/replaced.
So "w" means roughly:
start writing a fresh file.

24. .write()

python
f.write(text)
writes a string.
Example:
python
f.write("Hello")
writes five characters.

25. write() does not automatically add newline

This:
python
f.write("A")
f.write("B")
produces:
text
AB
not:
text
A
B
To separate lines:
python
f.write("A\n")
f.write("B\n")

26. Writing numbers

This is wrong:
python
f.write(42)
because write() expects text.
Convert:
python
f.write(str(42))
or use formatted strings.

27. Writing formatted output

python
name = "A"
mark = 85

f.write(f"{name},{mark}\n")
writes:
text
A,85
followed by newline.

28. Append mode

python
with open("log.txt", "a") as f:
    f.write("New entry\n")
adds data to the end instead of replacing existing contents.

29. Write vs append

Suppose file contains:
text
A
Using:
python
open(..., "w")
then writing B:
text
B
Using:
python
open(..., "a")
then writing B:
text
A
B
assuming appropriate newlines.

30. File mode choice

Ask:

Need existing contents?

Use read mode.

Need a fresh output file?

Use write mode.

Need to add to existing contents?

Use append mode.
Choosing the wrong mode can destroy data.

31. Reading all contents

python
with open("data.txt", "r") as f:
    text = f.read()
Now text is one string.
You can then use string operations:
python
words = text.split()

32. Word count

python
with open("data.txt", "r") as f:
    text = f.read()

words = text.split()

print(len(words))
This counts whitespace-separated tokens.

33. Character count

python
with open("data.txt", "r") as f:
    text = f.read()

print(len(text))
This counts characters in the string, including possible newlines.

34. Line count

python
count = 0

with open("data.txt", "r") as f:
    for line in f:
        count += 1

print(count)
Each iteration corresponds to one line.

35. Count non-empty lines

python
count = 0

with open("data.txt", "r") as f:
    for line in f:
        if line.strip() != "":
            count += 1
This filters blank/whitespace-only lines.

36. Search inside file

python
target = "Python"
found = False

with open("data.txt", "r") as f:
    for line in f:
        if target in line:
            found = True
            break
Same search + flag + break pattern as before.

37. Count matching lines

python
count = 0

with open("data.txt", "r") as f:
    for line in f:
        if "error" in line.lower():
            count += 1
This is simple log-file analysis.

38. Parsing delimited text

Suppose file contains:
text
A,80
B,92
C,70
Each line has:
text
name,mark
Read:
python
for line in f:
    parts = line.strip().split(",")
For first line:
python
parts == ["A", "80"]

39. Unpack parsed fields

python
name, mark = line.strip().split(",")
mark = int(mark)
Now:
text
name = "A"
mark = 80
This combines:
  • file iteration
  • string splitting
  • tuple unpacking
  • type conversion

40. Build a dictionary from file

python
marks = {}

with open("marks.txt", "r") as f:
    for line in f:
        name, mark = line.strip().split(",")
        marks[name] = int(mark)
File:
text
A,80
B,92
C,70
becomes:
python
{
    "A": 80,
    "B": 92,
    "C": 70
}

41. File → collection

A major Week 9 pattern is:
text
file
 ↓
read text
 ↓
parse
 ↓
convert datatypes
 ↓
build list/dictionary/set
Then all Week 6–8 collection algorithms become available.

42. Collection → file

The reverse pattern:
text
Python collection
 ↓
iterate
 ↓
format as text
 ↓
write
 ↓
file
Example:
python
marks = {
    "A": 80,
    "B": 92
}

with open("marks.txt", "w") as f:
    for name, mark in marks.items():
        f.write(f"{name},{mark}\n")

43. Round-trip idea

Data can flow:
file→Python objects→processing→file\boxed{ file \rightarrow Python\ objects \rightarrow processing \rightarrow file }
This is the basis of many real data pipelines.

44. CSV intuition

A simple CSV-like file:
text
name,mark,city
A,80,Delhi
B,92,Mumbai
Each row represents a record.
Each comma separates fields.
At a basic level:
python
parts = line.strip().split(",")
can parse simple examples.

45. Important CSV caveat

Real CSV files can contain:
  • quoted commas
  • escaped quotes
  • embedded newlines
So general-purpose CSV parsing should normally use Python's csv module rather than naive .split(",").
For basic teaching examples, however, simple split-based parsing may be sufficient if the file format guarantees no such complexities.

46. Header row

File:
text
name,mark
A,80
B,90
First line is metadata/header, not a student record.
One approach:
python
with open("marks.txt", "r") as f:
    header = f.readline()

    for line in f:
        ...
The first line is consumed separately.

47. File position

A file object tracks the current read position.
Suppose:
python
f.read()
reads the entire file.
A second:
python
f.read()
usually returns:
python
""
because you are already at end-of-file.

48. End-of-file

When there is nothing more to read, file reading reaches EOF:
text
End Of File
Iteration:
python
for line in f:
automatically stops at EOF.

49. .readline() at EOF

At end of file:
python
f.readline()
returns an empty string:
python
""
This can be used in manual reading loops.

50. Manual readline loop

python
line = f.readline()

while line != "":
    process(line)
    line = f.readline()
This is a classic EOF-controlled loop.

51. Prefer direct file iteration when appropriate

Instead of:
python
line = f.readline()

while line != "":
    ...
    line = f.readline()
often cleaner:
python
for line in f:
    ...
Use the form that best expresses the algorithm.

52. File pointer / cursor intuition

Think of the file object as maintaining a cursor:
text
A
B
C
^
Reading advances the cursor.
After reading A:
text
A
B
C
  ^
and so on.

53. .seek() supporting concept

Python can reposition the file cursor with operations such as:
python
f.seek(...)
For introductory work, the key idea is simply:
reading changes the file's current position.
Detailed random-access file handling can come later.

54. Text mode

Ordinary:
python
open("data.txt", "r")
opens in text mode.
Python returns strings.

55. Binary mode

Modes such as:
python
"rb"
"wb"
read/write raw bytes rather than text strings.
Useful for:
  • images
  • PDFs
  • binary formats
But basic Week 9 file exercises are likely text-focused.

56. Encoding intuition

Text on disk is represented using bytes.
An encoding such as UTF-8 defines how characters map to bytes.
Python can specify:
python
open("data.txt", "r", encoding="utf-8")
This becomes especially important for non-ASCII text.

57. File path

A filename may be:
python
"data.txt"
or a path:
python
"folder/data.txt"
The path tells the operating system where the file is located.

58. Relative path

python
"data.txt"
is typically interpreted relative to the program's current working directory.
So:
"file exists on my computer"
does not necessarily mean Python will find it from the current directory.

59. Absolute path intuition

An absolute path identifies a location from the filesystem root / full system location.
Exact syntax varies by operating system.
For course problems, file names are often provided directly so you do not need to manage complex paths.

60. Missing file

Opening:
python
open("missing.txt", "r")
when the file does not exist causes an exception/error.
This is different from simply reading an empty file.

61. Empty file vs missing file

Empty file

Exists but contains zero characters.
python
f.read()
returns:
python
""

Missing file

No such file exists at the requested path.
Opening for read fails.
Do not confuse the two cases.

62. Empty lines

A line containing only newline:
python
"\n"
is not equal to:
python
""
The first represents a blank line.
The second often represents no data/EOF in readline().

63. .strip() can blur this distinction

python
"\n".strip()
becomes:
python
""
So after stripping, an empty line and an originally empty string can look identical.
Know what stage of processing you are reasoning about.

64. Average numbers from file

Suppose:
text
10
20
30
40
Program:
python
total = 0
count = 0

with open("numbers.txt", "r") as f:
    for line in f:
        x = float(line.strip())
        total += x
        count += 1

if count > 0:
    print(total / count)
Output:
25.25.

65. Maximum from file

python
maximum = None

with open("numbers.txt", "r") as f:
    for line in f:
        x = float(line.strip())

        if maximum is None or x > maximum:
            maximum = x
This handles initialization without inventing an arbitrary starting maximum.

66. Why None helps

Before the first number is seen:
python
maximum = None
means:
no maximum has been established yet.
After first number:
python
maximum
becomes actual data.

67. Skip blank lines

python
with open("numbers.txt", "r") as f:
    for line in f:
        line = line.strip()

        if line == "":
            continue

        x = int(line)
This avoids attempting:
python
int("")
which would fail.

68. Filtering while reading

Suppose file contains many numbers but only positives matter:
python
positives = []

with open("numbers.txt", "r") as f:
    for line in f:
        x = int(line.strip())

        if x > 0:
            positives.append(x)
File processing uses the same filter pattern as lists.

69. Transform while reading

python
squares = []

with open("numbers.txt", "r") as f:
    for line in f:
        x = int(line.strip())
        squares.append(x ** 2)
Again:
read→transform→store\text{read}\rightarrow\text{transform}\rightarrow\text{store}

70. Frequency analysis from file

Suppose file contains words:
text
cat
dog
cat
bird
Program:
python
freq = {}

with open("words.txt", "r") as f:
    for line in f:
        word = line.strip()
        freq[word] = freq.get(word, 0) + 1
Result:
python
{
    "cat": 2,
    "dog": 1,
    "bird": 1
}

71. Word-frequency from normal prose

python
freq = {}

with open("text.txt", "r") as f:
    for line in f:
        words = line.lower().split()

        for word in words:
            freq[word] = freq.get(word, 0) + 1
This introduces nested iteration over:
text
file lines
    ↓
words inside each line

72. Nested loop structure

python
for line in f:
    for word in line.split():
        ...
Outer iteration:
each line.
Inner iteration:
each word on that line.
This is directly related to earlier nested loops.

73. Writing filtered output

Suppose copy only positive numbers:
python
with open("input.txt", "r") as src:
    with open("positive.txt", "w") as dst:
        for line in src:
            x = int(line.strip())

            if x > 0:
                dst.write(f"{x}\n")
This is a complete input → processing → output pipeline.

74. Two file handles

Here:
python
src
is input file.
python
dst
is output file.
They are separate file objects with separate modes and positions.

75. Copy a file conceptually

python
with open("source.txt", "r") as src:
    with open("copy.txt", "w") as dst:
        for line in src:
            dst.write(line)
Each input line is written unchanged.

76. Transform a file

python
with open("source.txt", "r") as src:
    with open("upper.txt", "w") as dst:
        for line in src:
            dst.write(line.upper())
This creates an uppercase-transformed version.

77. Append log entries

python
with open("log.txt", "a") as f:
    f.write("Program started\n")
Every execution can add another line rather than replacing prior history.
This is a natural use of append mode.

78. Writing a list

Suppose:
python
values = [10, 20, 30]
Write one per line:
python
with open("values.txt", "w") as f:
    for x in values:
        f.write(f"{x}\n")
File becomes:
text
10
20
30

79. Writing comma-separated values

python
values = [10, 20, 30]

with open("values.txt", "w") as f:
    f.write(",".join(str(x) for x in values))
File:
text
10,20,30
This combines:
  • conversion
  • generator/iteration
  • joining
  • file writing

80. Read comma-separated values

If file contains:
text
10,20,30
then:
python
with open("values.txt", "r") as f:
    text = f.read()

parts = text.strip().split(",")
values = [int(x) for x in parts]
Result:
python
[10, 20, 30]

81. Parsing pipeline

Always separate conceptually:
text
raw text
↓
split
↓
strings
↓
type conversion
↓
usable Python values
For:
text
A,80
we get:
python
["A", "80"]
then:
python
name = "A"
mark = 80

82. Serialization intuition

When converting Python data into file text:
text
Python object
↓
string representation / structured format
↓
bytes on disk
When reading:
text
bytes on disk
↓
text
↓
parse
↓
Python object
The broad idea is called serialization/deserialization, though advanced formats come later.

Common mistake: forget to close file
With manual:
python
f = open(...)
you should normally eventually call:
python
f.close()
Using:
python
with open(...) as f:
avoids this common mistake.

Common mistake: use
"w" when intending append
If you open an existing file with:
python
"w"
its previous contents can be lost.
Always check the intended mode before writing.

Common mistake: write number directly
Wrong:
python
f.write(100)
Correct:
python
f.write(str(100))
or:
python
f.write(f"{100}")

Common mistake: double-spaced output
Suppose:
python
line
already contains:
python
"\n"
Then:
python
print(line)
adds its own newline too.
This may visually produce blank lines.
Possible fix:
python
print(line, end="")
or:
python
print(line.strip())
depending on desired behavior.

Common mistake: strip before preserving formatting
If exact whitespace matters, this:
python
line.strip()
may remove meaningful spaces.
Use it only when such whitespace is irrelevant to the data.

Common mistake: convert before handling blank lines
Wrong:
python
x = int(line.strip())
if blank lines may exist.
Safer:
python
text = line.strip()

if text != "":
    x = int(text)

Common mistake: assume every row has enough fields
Suppose:
python
name, mark = line.strip().split(",")
but malformed line is:
text
A
There is only one field.
The unpacking fails.
Parsing assumes a particular file format; validate when needed.

Common mistake: assume every field converts successfully
python
mark = int(mark_text)
fails if file contains:
text
eighty
File input is external data and can be malformed.

Common mistake: read file twice without resetting
python
text1 = f.read()
text2 = f.read()
After the first call, cursor is already at EOF.
So text2 is typically:
python
""

Common mistake: confuse blank line with EOF
readline():
python
"\n"
means an actual blank line.
python
""
means no more data / EOF.
Different cases.

Common mistake: append without newline
Suppose existing file ends:
text
Hello
and you append:
python
f.write("World")
depending on the original ending, result could become:
text
HelloWorld
rather than separate lines.
Manage separators explicitly.

Common mistake: output format mismatch
Automated assessment may expect:
text
A,80
while your program writes:
text
A, 80
or:
text
Student A scored 80
Exact formatting matters just as it does with print().

95. Trace a file-processing program

File:
text
4
-2
7
0
Program:
python
total = 0
count = 0

with open("data.txt", "r") as f:
    for line in f:
        x = int(line)

        if x > 0:
            total += x
            count += 1

print(total, count)
Trace:
xPositive?totalcount
4Yes41
-2No41
7Yes112
0No112
Output:
text
11 2

96. Trace parse-and-group program

File:
text
A,10
B,5
A,7
Code:
python
totals = {}

with open("data.txt", "r") as f:
    for line in f:
        name, value = line.strip().split(",")
        value = int(value)

        totals[name] = totals.get(name, 0) + value
Trace:
text
{}
↓ A,10
{"A": 10}
↓ B,5
{"A": 10, "B": 5}
↓ A,7
{"A": 17, "B": 5}

97. Files connect earlier topics

Week 9 is mostly a new data source/sink around concepts you already know.

Strings

Raw file contents are text.

Lists

Store parsed lines/values.

Dictionaries

Aggregate keyed records.

Sets

Track unique file entries.

Loops

Process lines.

Conditionals

Filter/validate data.

Functions

Encapsulate file-processing operations.

98. File processing as streaming

Instead of:
text
load everything
then process
you can often:
text
read one record
↓
process it
↓
update summary
↓
discard it
↓
read next
This is useful for large datasets.

99. Core read pattern

python
with open("input.txt", "r") as f:
    for line in f:
        line = line.strip()

        # parse
        # process

100. Core write pattern

python
with open("output.txt", "w") as f:
    for item in values:
        f.write(f"{item}\n")

101. Core transform pattern

python
with open("input.txt", "r") as src:
    with open("output.txt", "w") as dst:
        for line in src:
            result = transform(line)
            dst.write(result)

102. Compact file cheat sheet

python
## read
with open("data.txt", "r") as f:
    text = f.read()
python
## line by line
with open("data.txt", "r") as f:
    for line in f:
        ...
python
## write fresh
with open("data.txt", "w") as f:
    f.write("hello\n")
python
## append
with open("data.txt", "a") as f:
    f.write("new line\n")
python
## parse simple comma-separated row
name, mark = line.strip().split(",")
mark = int(mark)

103. Mental checklist for file questions

When solving a file problem, identify:
  1. Which file?
  2. Read, write, or append?
  3. What format does each line have?
  4. Does each line contain strings or numbers?
  5. What parsing is required?
  6. What datatype conversion is required?
  7. What collection/accumulator should store state?
  8. What output format is required?
  9. Could the file be empty?
  10. Could blank/malformed lines matter?

104. Week 8 → Week 9 transition

Week 8:
text
data already exists as Python collections
Week 9:
text
persistent external data
        ↓
      files
        ↓
       text
        ↓
parse into Python collections
        ↓
      process
        ↓
write persistent output
So files connect your Python programs to data outside the program itself.

105. What you should actually master

By the end of Python Week 9, you should be comfortable with:
  1. Explaining why files are useful.
  2. Distinguishing persistent file data from variables in memory.
  3. Opening files with open().
  4. Understanding "r", "w", and "a".
  5. Reading whole files with .read().
  6. Reading individual lines.
  7. Iterating through a file line-by-line.
  8. Understanding newline characters.
  9. Using .strip() appropriately.
  10. Converting file text into integers/floats.
  11. Writing strings with .write().
  12. Adding newline characters explicitly.
  13. Understanding that "w" can overwrite existing data.
  14. Appending with "a".
  15. Using with open(...) for automatic closing.
  16. Parsing simple delimited records.
  17. Building lists/dictionaries from file data.
  18. Aggregating file data using counters/sums/frequencies.
  19. Writing collection contents back to files.
  20. Understanding EOF and file-position intuition.
  21. Distinguishing an empty file from a missing file.
  22. Avoiding common parsing and formatting mistakes.
If these are comfortable, Programming in Python Week 9 is under control.

Quick Recall & Flashcards

Test your active recall before proceeding to practice problems. Format:
Question :: Answer.
  • Week 9 Diagnostic: Why is it recommended to use with open('file.txt', 'r') as f: instead of f = open(...)? :: Answer: B — The with statement acts as a context manager that guarantees the file descriptor is closed when the block exits.
  • Week 9 Diagnostic: Which file open mode should be used to add data to an existing file without overwriting it? :: Answer: C — Mode 'a' (append) writes new data at the end of the file without clearing existing contents.

Practice & Self-Check

Attempt these diagnostic questions to verify your operational understanding.
1

Question 1

Why is it recommended to use with open('file.txt', 'r') as f: instead of f = open(...)?
MCQ
3 Unit Assessment
A. It runs in a separate thread
B. It automatically closes the file even if exceptions occur during processing
C. It converts text to JSON automatically
D. It disables file locking
2

Question 2

Which file open mode should be used to add data to an existing file without overwriting it?
MCQ
3 Unit Assessment
A. 'r'
B. 'w'
C. 'a'
D. 'x'

Active Recall Session

Document outline

Keep your place and jump directly to a heading.

Table of contents

No note selected

Open a chapter to see its outline, backlinks, and sources here.