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.
>>> guide = { ... "lessons": 18, ... "modules": 5, ... "python": "3.10+" ... } >>> guide["goal"] = "understand it"
Writing and Appending to Files in Python
Reading brings data from a file into your program. Writing sends data in the opposite direction. Python’s write() method writes one string at a time, writelines() accepts an iterable of strings, write mode replaces existing file contents, and append mode preserves what is already there while adding new output at the end.
with open(...) context-manager pattern from Lesson 12.write() sends a string to an open file
The write() method accepts a string and sends those characters to a file that was opened with a mode permitting output. In the simplest case, open a file with "w", call write(), and allow the context manager to close the file when the block ends.
Unlike print(), write() does not automatically add a newline. If you want one line to end before the next begins, include \n yourself.
with open("report.txt", "w", encoding="utf-8") as file:
file.write("alpha\n")
file.write("beta\n")
with open("report.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
alpha
beta
The second with block is only there to verify what was written. The first block performs the output. Both calls to write() receive strings, and each string includes its own newline.
write() does not behave like print(). It writes exactly the string you provide. No space separator and no trailing newline are added automatically.
Write mode replaces existing contents
The mode "w" is useful when the file should represent the program’s newest complete output. If the path does not exist, Python creates it. If it already exists, opening it in write mode truncates it immediately.
That means the destructive action happens at open(), not at the first call to write(). In verification, an existing file containing old data became zero bytes simply by opening it with "w" and then closing it without writing anything.
Use write mode when replacement is intentional. Do not casually test it against a file you need to preserve.
Append mode preserves old content
Append mode, "a", also allows writing and creates the file if it does not exist. The important difference is that output is placed at the end instead of replacing the previous contents.
with open("log.txt", "w", encoding="utf-8") as file:
file.write("first\n")
with open("log.txt", "a", encoding="utf-8") as file:
file.write("second\n")
with open("log.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
first
second
The first block creates a starting file. The second opens the same path in append mode and adds another line after the existing text. This makes append mode appropriate for logs, histories, simple journals, and other outputs where old records should remain intact.
writelines() accepts multiple strings
The writelines() method accepts an iterable whose elements are strings. A list of strings is a common beginner example. Despite the method name, writelines() does not add line breaks for you. If each string should appear on its own line, the strings themselves must include \n.
lines = ["north\n", "south\n", "east\n"]
with open("directions.txt", "w", encoding="utf-8") as file:
file.writelines(lines)
with open("directions.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
north
south
east
Because every element already ends with a newline, the file contains three visible lines. If the list were ["north", "south", "east"] instead, the resulting file would contain northsoutheast with no automatic separators.
A loop is often clearer than building newline strings first
When your program already has a list of values, you do not have to transform the whole collection before writing. A loop can format and write each value one at a time. This connects file output directly to the loop patterns from Module 2.
items = ["red", "green", "blue"]
with open("colors.txt", "w", encoding="utf-8") as file:
for item in items:
file.write(f"{item}\n")
with open("colors.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
red
green
blue
This pattern is especially useful when each value needs formatting, conversion, or additional text before it is written. The f-string produces a normal string, and write() sends that string to the file.
It also keeps the output rule close to the data transformation. If later you decide every line should include a label, timestamp, delimiter, or calculated value, you can change the single formatting expression inside the loop instead of rebuilding a separate list first. That makes loop-based writing a useful bridge between in-memory Python objects and a simple line-oriented text format.
file.write(text)Writes exactly the supplied string; no newline is added automatically.
file.writelines(strings)Writes each string from an iterable without inventing separators.
open(path, "w")Creates a new file or truncates an existing one.
open(path, "a")Creates the file if needed and writes at the end.
Text files still require strings
Text-mode file methods work with strings. If your program has an integer, float, or another non-string value, convert or format it before writing. An f-string is often the cleanest approach because it can combine labels, numbers, and newline characters in one expression.
For example, file.write(f"Score: {score}\n") works because the f-string evaluates to a string before write() receives it. Passing the integer directly does not.
Common mistakes while writing files
The four failures below were executed in Python. They show the two requirements that matter most: the file must be open in a mode that permits writing, and the values sent to text-mode write methods must be strings.
with open("report.txt", "r", encoding="utf-8") as file:
file.write("hello")
Traceback (most recent call last):
File "/tmp/ipykernel_313/4178984910.py", line 26, in run_err
exec(compile(code, str(work / filename), "exec"), {})
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/awm_lesson14/mistake1_write_read_mode.py", line 2, in <module>
io.UnsupportedOperation: not writable
The path is open successfully, but "r" does not grant write access. Use a mode that matches the operation you intend.
with open("numbers.txt", "w", encoding="utf-8") as file:
file.write(42)
Traceback (most recent call last):
File "/tmp/ipykernel_313/4178984910.py", line 26, in run_err
exec(compile(code, str(work / filename), "exec"), {})
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/awm_lesson14/mistake2_write_int.py", line 2, in <module>
TypeError: write() argument must be str, not int
Text-mode write() expects a string. Convert with str(42) or format the number inside an f-string.
with open("lines.txt", "w", encoding="utf-8") as file:
file.writelines([1, 2, 3])
Traceback (most recent call last):
File "/tmp/ipykernel_313/4178984910.py", line 26, in run_err
exec(compile(code, str(work / filename), "exec"), {})
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/awm_lesson14/mistake3_writelines_ints.py", line 2, in <module>
TypeError: write() argument must be str, not int
A list is a valid iterable, but its elements must still be strings. The container type alone does not make its contents writable as text.
with open("closed.txt", "w", encoding="utf-8") as file:
pass
file.write("late")
Traceback (most recent call last):
File "/tmp/ipykernel_313/4178984910.py", line 26, in run_err
exec(compile(code, str(work / filename), "exec"), {})
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/awm_lesson14/mistake4_write_after_with.py", line 3, in <module>
ValueError: I/O operation on closed file.
The variable still refers to the file object after the block, but the context manager has closed its underlying resource. Keep the write operations inside the managed lifetime.
Supporting classroom explanation
This page is original A Wandering Mind instructional material. The assigned CPSC 1301K lecture below reinforces the core mechanics of sending text from a running program into a file.
What it adds: a focused classroom walkthrough of opening a file for output and writing program data into it.
Try it yourself
Use disposable practice files while learning write mode. Predict the final file contents before opening the answer.
Exercise 1 · Write one message
Create message.txt, write Hello, Python! followed by a newline, then reopen the file and print the saved text.
Show one answer
with open("message.txt", "w", encoding="utf-8") as file:
file.write("Hello, Python!\n")
with open("message.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
Hello, Python!
Exercise 2 · Append a second event
Create events.txt containing start, then reopen it in append mode and add finish. Print the final file contents.
Show one answer
with open("events.txt", "w", encoding="utf-8") as file:
file.write("start\n")
with open("events.txt", "a", encoding="utf-8") as file:
file.write("finish\n")
with open("events.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
start
finish
Exercise 3 · Write several names
Create a list containing "Ada\n", "Grace\n", and "Linus\n". Write the list with writelines(), then reopen and print the file.
Show one answer
names = ["Ada\n", "Grace\n", "Linus\n"]
with open("names.txt", "w", encoding="utf-8") as file:
file.writelines(names)
with open("names.txt", "r", encoding="utf-8") as file:
print(file.read().strip())
Ada
Grace
Linus
Module 3 complete: what comes next
You can now open, close, read, loop over, write, and append to text files using context managers. You also understand the major file modes and why write mode must be treated carefully. Those pieces are enough to build simple persistent programs that store information outside the current Python process.
Module 4 focuses on what happens when operations fail. Continue to Handling Exceptions in Python to learn how try, except, else, and finally let a program respond to predictable failures without immediately crashing.
