When you need to append data files in Python, you use a different mode than writing from scratch. Most programs that write files do so in one of two patterns. Some programs generate a complete output file from scratch each time they run: a report with the latest numbers, a transformed version of an input file, or an exported dataset that replaces the previous export. These programs open files in write mode, which truncates the file before writing and produces a clean, complete result every time. Other programs need to add to a file without disturbing what is already there: a log that records every run of a nightly script, a data collection file that accumulates sensor readings, or a journal where each entry extends the file instead of replacing it. These programs open files in append mode, and the difference between the two is the difference between a complete record and an empty file that only contains the most recent entry.
Python append data files using append mode is the safer default when you are not sure whether existing content should be preserved. If the file does not exist yet, append mode creates it, just like write mode does. If the file already exists, append mode opens it and positions the write pointer at the very end, so every byte you write lands after the last byte of existing content. You cannot accidentally overwrite old data in append mode because Python does not let you move the write pointer backward; all writes go to the end, regardless of where you might have read from if you opened in a read-and-append mode. This protection makes append mode the right choice for logs, audit trails, data pipelines that accumulate results over time, and any workflow where losing old data is unacceptable.
How append mode works
When you open a file with append mode, Python checks whether the file exists. If it does not, Python creates an empty file and positions the write pointer at byte zero, which is also the end because the file is empty. If the file does exist, Python opens it without truncation and positions the write pointer immediately after the last byte of existing content. Every call to write or writelines adds bytes starting from that position, and the write pointer advances forward with each write so the next call picks up where the previous one left off.
with open("events.log", "a", encoding="utf-8") as file:
file.write("User logged in.\n")Run this code once, and events.log contains a single line. Run it again, and the file contains two identical lines, one from each execution. Run it a hundred times, and you have a hundred-line log file with a complete record of every time the script executed. No special loop, no counter, and no file management beyond the single open call with append mode is required. The file grows by exactly the bytes you write each time, and the existing content is never at risk.
The simplicity of this pattern hides an important detail: in append mode, every write goes to the end regardless of the file object's current position. Even if you attempt to move the position elsewhere, a subsequent write still appends to the end. This is a deliberate design choice in Python's file implementation. Append mode guarantees that writes are always atomic appends from the operating system's perspective, which prevents multiple processes writing to the same file from overwriting each other's data. If you need to both read existing content and then append, open the file twice: once in read mode to read the old content, and then again in append mode to write the new content.
Practical append patterns
The most common use of append mode is logging. A program records what it did, when it did it, and whether anything went wrong, and each run adds a new block of entries to the same log file. Over days or weeks, the log grows into a detailed history that you can search through when you need to debug a problem or understand how the system has been used. Adding a timestamp to each entry makes the log self-documenting and is straightforward with Python's datetime module.
from datetime import datetime
def log_event(message):
timestamp = datetime.now().isoformat()
with open("app.log", "a", encoding="utf-8") as file:
file.write(f"[{timestamp}] {message}\n")
log_event("Application started.")
log_event("Processing data file.")
log_event("Application finished successfully.")The log_event function encapsulates the append pattern so the rest of your code calls a clean function without repeating the file mode and encoding each time. Each call opens the file, appends a single timestamped line, and closes the file. For a small script that logs a handful of events per run, this pattern is perfectly adequate. For a high-throughput application that logs thousands of events per second, you would switch to Python's built-in logging module, which handles batching, rotation, and concurrency for you. But the mental model is the same: new records go to the end of the file, and old records stay put.
Another common pattern is data accumulation, where each run of a program adds new rows to a CSV file. A weather station script that runs every hour appends the latest temperature and humidity readings. A web scraper that checks a product page daily appends the current price to a price history file. In each case, append mode ensures that every reading is preserved in order and that no gap appears because one run accidentally overwrote the previous one. The csv module's DictWriter works with append mode just as it works with write mode. The file grows by one row each time the script runs, and if the file does not exist on the first run, append mode creates it automatically.
When not to use append mode
Append mode is the wrong choice when you want the output file to represent a complete, current snapshot of some data. If your program generates a report that should always reflect the latest state, opening in write mode ensures that stale data from a previous run is erased before the new report is written. If you append a new report to an old report, the file grows without bound and contains contradictory information from different points in time, which confuses anyone or any program that reads it later.
Append mode is also the wrong choice when your writes are not idempotent, meaning each run adds content that should not be duplicated. If your program processes a batch of transactions and appends a summary line for each one, and you accidentally run the program twice against the same input, you get duplicate summary lines in the output file. With write mode, the second run would replace the first run's output entirely, and the duplicate would be harmless because it replaces rather than accumulates. The choice between write mode and append mode is ultimately a question of what the file represents: a snapshot of the latest computation, or a cumulative record of every computation that has ever run.
Combining append with other file handling skills
Append mode works with every file method you have learned so far. The write method adds a string at the end, and writelines adds a sequence of strings at the end. You can open a file in append mode with an explicit encoding to handle international text correctly, or in binary append mode to add raw bytes to a binary file. The with statement you will learn about in detail in the article on using the Python with statement for files works with append mode exactly as it does with read and write modes, guaranteeing that the file is closed and flushed even if an error interrupts your append operation.
If you need to read a file before appending to it, for example to check whether a certain entry already exists before adding it, you have two options. You can open the file twice: first in read mode to check the existing content, and then in append mode to add the new entry if needed. Or you can open the file once in read-and-append mode, which allows both operations on the same handle, but you must reposition the read pointer to the beginning before reading because the file position starts at the end. The two-open approach is often simpler to reason about because it keeps the read and write phases separate.
Appending is the last of the core file writing operations. Combined with the reading techniques from the article on reading files in Python and the foundational open and close knowledge from the article on opening and closing files in Python, you now have the complete set of basic file handling tools. The remaining articles in this section will deepen these skills with file modes, path handling, the with statement, error handling, and strategies for working with large files efficiently.
Rune AI
Key Insights
- Append mode 'a' writes new content at the end of the file without erasing existing data.
- Like write mode, 'a' creates the file if it does not exist, so it is safe to use on first runs.
- Use append mode for logs, journals, data collection, and any file that grows incrementally.
- The write() method works identically in append and write modes; only where the data lands differs.
- Pair append mode with the with statement for automatic closing and data safety.
Frequently Asked Questions
What is the difference between write mode 'w' and append mode 'a'?
Can I read from a file opened in append mode?
Does append mode create a file if it does not exist?
Conclusion
Append mode is the safe way to add content to a file without risking existing data. Use it for logs that grow over time, data files that accumulate records across multiple program runs, and any situation where each write should extend the file rather than replace it. The same write() and writelines() methods work in append mode, but the file pointer starts at the end and every write goes there, protecting the content that came before.
More in this topic
Create Custom Iterators in Python
Learn how to build your own iterators in Python by implementing the __iter__() and __next__() methods, with practical examples and reusable patterns.
Python Iterator Protocol Explained
Learn how Python's iterator protocol works with the __iter__() and __next__() methods, and understand the contract every iterator must follow.
Python Iterables and Iterators Explained
Learn what iterables and iterators are in Python, how they power for loops under the hood, and why understanding them unlocks cleaner data processing patterns.