Every time you call the open function in Python, the second argument you pass is a mode string that tells Python exactly what you intend to do with the file. Python file modes are a small language of their own: a handful of characters that you combine to express read, write, append, exclusive creation, text processing, and binary access. Choosing the wrong mode can destroy data before you have written a single byte, prevent you from reading a file that exists, or silently create an empty file when you expected an error. Understanding the full set of modes and their interactions is one of the highest-leverage investments you can make in your file handling skills, because every subsequent operation you perform on a file is constrained by the mode you chose when you opened it.
The previous articles in this section covered the practical use of each mode in context: you saw read mode when reading files in Python, write mode when writing files in Python, and append mode when appending data to files in Python. This article pulls back and gives you the complete reference. By the end, you will understand every valid mode string, what each character contributes, how modes interact with file existence and file position, and how to choose the right combination for any real-world file operation.
The four base modes
Python has four base mode characters, and every valid mode string starts with one of them. The r mode opens a file for reading. It is the only base mode that requires the file to already exist; if the file is missing, open raises a FileNotFoundError. Because reading cannot modify data, r is the safest default and the mode Python uses when you omit the second argument entirely.
The w mode opens a file for writing. If the file exists, Python truncates it to zero length immediately upon opening, erasing all existing content before your code writes anything new. If the file does not exist, Python creates an empty file. This truncation behavior is the most dangerous surprise in file handling: opening a file you meant to read with w destroys its contents silently and instantly. The w mode is correct when you want a fresh output file each time your program runs, but it is catastrophic when you intended to preserve existing data.
The a mode opens a file for appending. It creates the file if it does not exist, and if the file does exist, it positions the write pointer at the end without truncating anything. Every byte you write lands after the last byte of existing content, and Python prevents you from writing anywhere else regardless of where you reposition the pointer. Append mode is the safe choice for logs, journals, data accumulation, and any workflow where each run should add to the file without touching what came before.
The x mode opens a file for exclusive creation. It is similar to w in that it opens for writing and creates the file if it does not exist, but it differs in one critical way: if the file already exists, open raises a FileExistsError instead of truncating. This makes x mode the right choice when you are generating output files and want a hard guarantee that you are not overwriting previous work. Combined with error handling, x mode lets you write programs that refuse to clobber existing data.
try:
with open("output.txt", "x") as file:
file.write("Fresh content.\n")
except FileExistsError:
print("output.txt already exists. Skipping.")This pattern is useful in batch processing pipelines where multiple runs might target the same output filename. The exclusive creation mode acts as a built-in guard that prevents one run from silently destroying another run's results. If you need to overwrite, you switch to w mode explicitly, making the destructive intent visible in the code.
The plus variants: adding the complementary operation
Adding a plus character to any base mode enables both reading and writing on the same file handle. The r+ mode opens for reading and writing without truncation. The file must exist, and after opening, the file pointer sits at the beginning. You can read from the current position, seek to any location, and write at the current position. This is the mode you use when you need to update parts of an existing file in place, such as modifying a specific record in a data file without rewriting the entire thing.
The w+ mode opens for both reading and writing but still truncates the file first, just like plain w. After truncation, the file is empty, and both the read and write pointers start at byte zero. Reading immediately after opening returns nothing because the file is empty. This mode is less commonly used than r+ because truncating and then reading is rarely useful, but it exists for completeness and for cases where you want a single handle that can both populate a new file and then read back what you wrote without reopening.
The a+ mode opens for both reading and appending. The file is created if it does not exist, and existing content is preserved. The write pointer is locked to the end, so all writes append. The read pointer starts at the end as well, which means you must call seek with an argument of zero to reposition to the beginning before reading. After reading, subsequent writes still go to the end, not to wherever you left the read pointer. This separation of read position from write position is unique to append modes and is enforced by the operating system, not just by Python.
The x+ mode combines exclusive creation with read access. Like plain x, it raises FileExistsError if the file already exists. Like x, it creates the file if it does not exist. The plus gives you the ability to read back what you write, which is occasionally useful for verification workflows where you write data and immediately check that it was written correctly before closing.
Binary mode: the b character
Adding a b to any mode string switches from text mode to binary mode. Binary mode reads and writes bytes objects instead of strings, performs no encoding or decoding, and does not translate line endings between platforms. The valid binary mode strings are rb, wb, ab, xb, and their plus variants rb+, wb+, ab+, and xb+.
Binary mode is required for any file format that is not plain text. Images, audio files, video files, PDF documents, compiled executables, compressed archives, and serialized data like pickle files all contain bytes that do not map to meaningful characters. Opening such a file in text mode causes Python to attempt UTF-8 decoding on the raw bytes, which either fails with a UnicodeDecodeError or produces garbled text.
with open("data.bin", "wb") as file:
file.write(b'\x00\x01\x02\x03')
with open("data.bin", "rb") as file:
raw = file.read()
print(type(raw))
print(raw)The first block writes four bytes to a binary file. The second block reads them back as a bytes object. If you had opened the file in text mode w instead of binary mode wb, Python would have rejected the bytes literal with a TypeError because text mode expects strings. This type checking catches mode mismatches at the point of the write call rather than letting corrupted data reach the disk.
How mode, existence, and position interact
The mode you choose determines three things simultaneously: whether the file must already exist, where the file pointer starts, and whether writes are allowed to move the pointer backward. For the read modes r and r+, the file must exist and the pointer starts at the beginning. For write modes w, w+, and x, x+, the file is created if missing and the pointer starts at the beginning, but w and w+ also truncate existing files. For append modes a and a+, the file is created if missing, the write pointer starts at the end and stays there, and the read pointer also starts at the end but can be repositioned with seek.
These rules are consistent across all operating systems that Python supports, which means code that opens files correctly on your development machine will behave the same way on a Linux server, a Windows desktop, or a macOS laptop. The encoding parameter is the main platform-sensitive variable, and you control it explicitly by passing encoding="utf-8" whenever you open a text file. Binary mode removes encoding from the equation entirely, which is one reason it is preferred for data interchange formats where you want byte-identical output regardless of platform.
One subtlety worth noting is that the truncation in w and w+ modes happens at the operating system level when the file is opened, not when the first write occurs. This means that even if your program crashes immediately after opening a file in write mode and before writing anything, the original file content is already gone. There is no undo. This is another reason to prefer the with statement, which at least guarantees that the file handle is released properly, though it cannot restore data that was already truncated at open time.
Understanding file modes completes the foundation you built in the articles on opening and closing files in Python and reading files in Python. With the mode reference in hand, you can now open any file with confidence, knowing exactly what permissions you are requesting and what guarantees Python and the operating system provide in return.
Rune AI
Key Insights
- The four base modes are r (read), w (write with truncation), a (append), and x (exclusive create).
- Adding + to a mode enables both reading and writing on the same file handle.
- Binary mode (rb, wb, etc.) bypasses text encoding and works with bytes objects.
- r and r+ require the file to exist; w, w+, a, a+, x, and x+ create it if missing.
- x mode is unique in raising FileExistsError if the file already exists, protecting against accidental overwrites.
Frequently Asked Questions
What is the difference between r+ and w+ file modes?
When should I use binary mode instead of text mode?
Does opening a file in a+ mode let me read from the beginning?
Conclusion
Python file modes are a compact but precise system for declaring what you intend to do with a file. The base modes cover the four fundamental operations: read, write, append, and exclusive create. The plus variants add the complementary operation, and binary mode switches from strings to bytes. Understanding the full set of modes gives you confidence to open any file correctly on the first try.
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.