Week 9: File Operations & Context Managers
4443 words
22 min read
2026-09-12T00:00:00.000Z
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:
pythonmarks = [80, 90, 75]
When the program ends, that in-memory state disappears.
Files let programs work with persistent data:
textdisk 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:
1. What is a file?
A file is persistent data stored outside the program's temporary memory.
Examples:
textmarks.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:
pythontotal = 420
If the program exits,
total disappears from memory.If you save it:
textresult.txt
another program—or the same program later—can read it again.
3. Basic file workflow
A file operation usually follows:
text1. Open file 2. Perform operation 3. Close file
Example:
pythonf = open("data.txt", "r") content = f.read() f.close()
4. open()
Python's basic file-opening function is:
pythonopen(filename, mode)
Example:
pythonf = open("data.txt", "r")
This returns a file object referenced by:
pythonf
5. File modes
Important modes include:
| Mode | Meaning |
|---|---|
"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
pythonf = open("data.txt", "r")
means:
open an existing file for reading.
If the file does not exist, opening usually raises an error.
7. .read()
pythoncontent = f.read()
reads the remaining file contents as a string.
Suppose
data.txt contains:texthello world
Then:
pythoncontent = 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:
texthello world
9. .readline()
pythonline = f.readline()
reads one line at a time.
Suppose:
textA B C
Then successive calls conceptually return:
python"A\n" "B\n" "C\n"
10. .readlines()
pythonlines = 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:
pythonfor 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:
pythoncontent = f.read()
is fine.
For a very large file, reading line-by-line can be more memory-efficient:
pythonfor 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:
pythonline = 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:
text10 20 30
Program:
pythonf = open("numbers.txt", "r") for line in f: line = line.strip() print(line) f.close()
Output:
text10 20 30
16. File text is still text
Even if a line contains:
text25
reading it gives something like:
python"25\n"
not integer:
python25
So numerical processing needs conversion.
17. Convert lines to integers
pythonf = open("numbers.txt", "r") total = 0 for line in f: x = int(line.strip()) total += x f.close() print(total)
If file contains:
text10 20 30
result:
18. Same accumulator patterns still apply
File input changes where data comes from.
The algorithm remains familiar:
pythontotal = 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:
pythonwith 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:
pythonf = open("data.txt", "r") ... f.close()
use:
pythonwith open("data.txt", "r") as f: ...
It reduces the risk of forgetting to close the file.
21. Scope of the with block
pythonwith 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
pythonwith open("output.txt", "w") as f: f.write("hello")
This writes:
texthello
to the file.
23. "w" can overwrite
This is critical.
If
output.txt already contains:textOLD DATA
and you open:
pythonopen("output.txt", "w")
the previous contents are normally truncated/replaced.
So
"w" means roughly:start writing a fresh file.
24. .write()
pythonf.write(text)
writes a string.
Example:
pythonf.write("Hello")
writes five characters.
25. write() does not automatically add newline
This:
pythonf.write("A") f.write("B")
produces:
textAB
not:
textA B
To separate lines:
pythonf.write("A\n") f.write("B\n")
26. Writing numbers
This is wrong:
pythonf.write(42)
because
write() expects text.Convert:
pythonf.write(str(42))
or use formatted strings.
27. Writing formatted output
pythonname = "A" mark = 85 f.write(f"{name},{mark}\n")
writes:
textA,85
followed by newline.
28. Append mode
pythonwith 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:
textA
Using:
pythonopen(..., "w")
then writing
B:textB
Using:
pythonopen(..., "a")
then writing
B:textA 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
pythonwith open("data.txt", "r") as f: text = f.read()
Now
text is one string.You can then use string operations:
pythonwords = text.split()
32. Word count
pythonwith open("data.txt", "r") as f: text = f.read() words = text.split() print(len(words))
This counts whitespace-separated tokens.
33. Character count
pythonwith open("data.txt", "r") as f: text = f.read() print(len(text))
This counts characters in the string, including possible newlines.
34. Line count
pythoncount = 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
pythoncount = 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
pythontarget = "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
pythoncount = 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:
textA,80 B,92 C,70
Each line has:
textname,mark
Read:
pythonfor line in f: parts = line.strip().split(",")
For first line:
pythonparts == ["A", "80"]
39. Unpack parsed fields
pythonname, mark = line.strip().split(",") mark = int(mark)
Now:
textname = "A" mark = 80
This combines:
- file iteration
- string splitting
- tuple unpacking
- type conversion
40. Build a dictionary from file
pythonmarks = {} with open("marks.txt", "r") as f: for line in f: name, mark = line.strip().split(",") marks[name] = int(mark)
File:
textA,80 B,92 C,70
becomes:
python{ "A": 80, "B": 92, "C": 70 }
41. File → collection
A major Week 9 pattern is:
textfile ↓ read text ↓ parse ↓ convert datatypes ↓ build list/dictionary/set
Then all Week 6–8 collection algorithms become available.
42. Collection → file
The reverse pattern:
textPython collection ↓ iterate ↓ format as text ↓ write ↓ file
Example:
pythonmarks = { "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:
This is the basis of many real data pipelines.
44. CSV intuition
A simple CSV-like file:
textname,mark,city A,80,Delhi B,92,Mumbai
Each row represents a record.
Each comma separates fields.
At a basic level:
pythonparts = 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:
textname,mark A,80 B,90
First line is metadata/header, not a student record.
One approach:
pythonwith 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:
pythonf.read()
reads the entire file.
A second:
pythonf.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:
textEnd Of File
Iteration:
pythonfor line in f:
automatically stops at EOF.
49. .readline() at EOF
At end of file:
pythonf.readline()
returns an empty string:
python""
This can be used in manual reading loops.
50. Manual readline loop
pythonline = 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:
pythonline = f.readline() while line != "": ... line = f.readline()
often cleaner:
pythonfor 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:
textA B C ^
Reading advances the cursor.
After reading A:
textA B C ^
and so on.
53. .seek() supporting concept
Python can reposition the file cursor with operations such as:
pythonf.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:
pythonopen("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:
pythonopen("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:
pythonopen("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.
pythonf.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:
text10 20 30 40
Program:
pythontotal = 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:
65. Maximum from file
pythonmaximum = 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:
pythonmaximum = None
means:
no maximum has been established yet.
After first number:
pythonmaximum
becomes actual data.
67. Skip blank lines
pythonwith open("numbers.txt", "r") as f: for line in f: line = line.strip() if line == "": continue x = int(line)
This avoids attempting:
pythonint("")
which would fail.
68. Filtering while reading
Suppose file contains many numbers but only positives matter:
pythonpositives = [] 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
pythonsquares = [] with open("numbers.txt", "r") as f: for line in f: x = int(line.strip()) squares.append(x ** 2)
Again:
70. Frequency analysis from file
Suppose file contains words:
textcat dog cat bird
Program:
pythonfreq = {} 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
pythonfreq = {} 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:
textfile lines ↓ words inside each line
72. Nested loop structure
pythonfor 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:
pythonwith 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:
pythonsrc
is input file.
pythondst
is output file.
They are separate file objects with separate modes and positions.
75. Copy a file conceptually
pythonwith 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
pythonwith 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
pythonwith 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:
pythonvalues = [10, 20, 30]
Write one per line:
pythonwith open("values.txt", "w") as f: for x in values: f.write(f"{x}\n")
File becomes:
text10 20 30
79. Writing comma-separated values
pythonvalues = [10, 20, 30] with open("values.txt", "w") as f: f.write(",".join(str(x) for x in values))
File:
text10,20,30
This combines:
- conversion
- generator/iteration
- joining
- file writing
80. Read comma-separated values
If file contains:
text10,20,30
then:
pythonwith 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:
textraw text ↓ split ↓ strings ↓ type conversion ↓ usable Python values
For:
textA,80
we get:
python["A", "80"]
then:
pythonname = "A" mark = 80
82. Serialization intuition
When converting Python data into file text:
textPython object ↓ string representation / structured format ↓ bytes on disk
When reading:
textbytes 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:
pythonf = open(...)
you should normally eventually call:
pythonf.close()
Using:
pythonwith open(...) as f:
avoids this common mistake.
Common mistake: use
"w" when intending appendIf 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:
pythonf.write(100)
Correct:
pythonf.write(str(100))
or:
pythonf.write(f"{100}")
Common mistake: double-spaced output
Suppose:
pythonline
already contains:
python"\n"
Then:
pythonprint(line)
adds its own newline too.
This may visually produce blank lines.
Possible fix:
pythonprint(line, end="")
or:
pythonprint(line.strip())
depending on desired behavior.
Common mistake: strip before preserving formatting
If exact whitespace matters, this:
pythonline.strip()
may remove meaningful spaces.
Use it only when such whitespace is irrelevant to the data.
Common mistake: convert before handling blank lines
Wrong:
pythonx = int(line.strip())
if blank lines may exist.
Safer:
pythontext = line.strip() if text != "": x = int(text)
Common mistake: assume every row has enough fields
Suppose:
pythonname, mark = line.strip().split(",")
but malformed line is:
textA
There is only one field.
The unpacking fails.
Parsing assumes a particular file format; validate when needed.
Common mistake: assume every field converts successfully
pythonmark = int(mark_text)
fails if file contains:
texteighty
File input is external data and can be malformed.
Common mistake: read file twice without resetting
pythontext1 = 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:
textHello
and you append:
pythonf.write("World")
depending on the original ending, result could become:
textHelloWorld
rather than separate lines.
Manage separators explicitly.
Common mistake: output format mismatch
Automated assessment may expect:
textA,80
while your program writes:
textA, 80
or:
textStudent A scored 80
Exact formatting matters just as it does with
print().95. Trace a file-processing program
File:
text4 -2 7 0
Program:
pythontotal = 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:
x | Positive? | total | count |
|---|---|---|---|
| 4 | Yes | 4 | 1 |
| -2 | No | 4 | 1 |
| 7 | Yes | 11 | 2 |
| 0 | No | 11 | 2 |
Output:
text11 2
96. Trace parse-and-group program
File:
textA,10 B,5 A,7
Code:
pythontotals = {} 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:
textload everything then process
you can often:
textread one record ↓ process it ↓ update summary ↓ discard it ↓ read next
This is useful for large datasets.
99. Core read pattern
pythonwith open("input.txt", "r") as f: for line in f: line = line.strip() # parse # process
100. Core write pattern
pythonwith open("output.txt", "w") as f: for item in values: f.write(f"{item}\n")
101. Core transform pattern
pythonwith 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:
- Which file?
- Read, write, or append?
- What format does each line have?
- Does each line contain strings or numbers?
- What parsing is required?
- What datatype conversion is required?
- What collection/accumulator should store state?
- What output format is required?
- Could the file be empty?
- Could blank/malformed lines matter?
104. Week 8 → Week 9 transition
Week 8:
textdata already exists as Python collections
Week 9:
textpersistent 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:
- Explaining why files are useful.
- Distinguishing persistent file data from variables in memory.
- Opening files with
open(). - Understanding
"r","w", and"a". - Reading whole files with
.read(). - Reading individual lines.
- Iterating through a file line-by-line.
- Understanding newline characters.
- Using
.strip()appropriately. - Converting file text into integers/floats.
- Writing strings with
.write(). - Adding newline characters explicitly.
- Understanding that
"w"can overwrite existing data. - Appending with
"a". - Using
with open(...)for automatic closing. - Parsing simple delimited records.
- Building lists/dictionaries from file data.
- Aggregating file data using counters/sums/frequencies.
- Writing collection contents back to files.
- Understanding EOF and file-position intuition.
- Distinguishing an empty file from a missing file.
- 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 off = open(...)? :: Answer: B — Thewithstatement 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'