Python Basics #18 — File Read/Write Vol. 2

5 min read

Continuing from the previous lesson, this lesson covers writing files. If you haven’t read the previous lesson, please start there first:

Python Basics #17 — File Read/Write Vol. 1

File read/write modes #

ModeDescription
rRead-only (default — can be omitted).
wWrite-only. Creates a new file if one with the same name doesn’t exist; otherwise overwrites. Overwriting deletes existing data — be careful.
xWrite-only, but raises an error if a file with the same name exists. Think of it as a safer w.
aAppend. Creates a new file if one with the same name doesn’t exist; otherwise appends to the end.
tText mode (default — can be omitted).
bBinary mode. For non-text files like PDFs and images.
r+Read and write simultaneously.
w+Read and write simultaneously.

Writing files is similar to reading. As with reading, use the open function. For the mode parameter, use one of w, x, or a.

Let’s write a file using w. To write, use the write method on the file object. write takes a string and writes it to the file.

Python code
with open(file='out.txt', mode='w', encoding='utf8') as file:
    file.write('line one')
    file.write('line two')
out.txt
line oneline two

We meant to write two lines, but they ended up on one. write doesn’t add a newline. Add \n characters explicitly to fix it:

Python code
with open(file='out.txt', mode='w', encoding='utf8') as file:
    file.write('line one\n')
    file.write('line two\n')
out.txt
line one
line two

If adding newlines every time feels tedious, use print instead. Let’s check print’s help:

Python shell
help(print)
Console output
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

print defaults end to a newline character and file to sys.stdout. sys.stdout is essentially the command prompt or terminal. If you pass a file object as the file argument, the string is written to the file instead of the console — and you don’t need to add a trailing \n each time.

Python code
with open(file='out.txt', mode='w', encoding='utf8') as file:
    print('line 1', file=file)
    print('line 2', file=file)
out.txt
line 1
line 2

Note: each time you re-run the code, the previous file contents are wiped and replaced by new text. With w mode, if out.txt doesn’t exist a new file is created; if it does exist, it gets overwritten — all previous contents are deleted. Be careful not to accidentally lose data.

Now let’s write a list of dictionaries (country information) to a file:

Python code
countries = [
    {'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'},
    {'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'},
    {'country': 'China', 'capital': 'Beijing', 'region': 'Asia'},
]

with open(file='country.txt', mode='w', encoding='utf8') as file:
    for country in countries:
        line = 'country: {country}, capital: {capital}, region: {region}\n'.format(**country)
        file.write(line)
country.txt
country: South Korea, capital: Seoul, region: Asia
country: Japan, capital: Tokyo, region: Asia
country: China, capital: Beijing, region: Asia

Saved correctly. To save a list or dictionary from your program to a text file, you can use the str function:

Python code
countries = [
    {'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'},
    {'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'},
    {'country': 'China', 'capital': 'Beijing', 'region': 'Asia'},
]

with open(file='country.txt', mode='w', encoding='utf8') as file:
    file.write(str(countries))
country.txt
[{'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'}, {'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'}, {'country': 'China', 'capital': 'Beijing', 'region': 'Asia'}]

The list object was saved in code form. But when you read this back, the Python interpreter doesn’t recognize it as a list — it returns a string. Confirm:

Python code
countries = [
    {'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'},
    {'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'},
    {'country': 'China', 'capital': 'Beijing', 'region': 'Asia'},
]

with open(file='country.txt', mode='r', encoding='utf8') as file:
    result = file.read()
    print(type(result))
Console output
<class 'str'>

To re-use saved data in your program, convert it back to a list or dictionary using the eval function:

Python code
countries = [
    {'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'},
    {'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'},
    {'country': 'China', 'capital': 'Beijing', 'region': 'Asia'},
]

with open(file='country.txt', mode='r', encoding='utf8') as file:
    result = file.read()
    result = eval(result)
    print(type(result))
Console output
<class 'list'>

Now that it’s a list object, you can use it just like the original:

Python code
countries = [
    {'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'},
    {'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'},
    {'country': 'China', 'capital': 'Beijing', 'region': 'Asia'},
]

with open(file='country.txt', mode='r', encoding='utf8') as file:
    result = file.read()
    result = eval(result)
    for country in result:
        print(country)
Console output
{'country': 'South Korea', 'capital': 'Seoul', 'region': 'Asia'}
{'country': 'Japan', 'capital': 'Tokyo', 'region': 'Asia'}
{'country': 'China', 'capital': 'Beijing', 'region': 'Asia'}

Now the x option. As mentioned, x is a safer version of w: if a file with the same name exists, it raises an error — preventing accidental data loss.

Python code
with open(file='country.txt', mode='x', encoding='utf8') as file:
    file.write('new data')
Console output
---------------------------------------------------------------------------
FileExistsError                           Traceback (most recent call last)
<ipython-input-9-e897f33b1472> in <module>
----> 1 with open(file='country.txt', mode='x', encoding='utf8') as file:
      2     file.write('new data')

FileExistsError: [Errno 17] File exists: 'country.txt'

FileExistsError was raised and the program terminated.

Now the a option. a is append mode. If a file with the same name doesn’t exist, it creates one. If it does exist, instead of overwriting (like w), it places the cursor at the end of the file and continues writing from there.

append.txt
existing data

Append text to append.txt using a:

Python code
with open(file='append.txt', mode='a', encoding='utf8') as file:
    file.write('appended text')
append.txt
existing dataappended text

The new text was written on the same line as the existing data. When appending, check whether the existing text ends with a newline; if not, prepend a newline to your new text:

Python code
with open(file='append.txt', mode='a', encoding='utf8') as file:
    file.write('\nappended text')
append.txt
existing data
appended text

That wraps up plain text reading and writing. Special formats like CSV, JSON, YAML, and EXCEL will be covered in separate lessons.

The next post covers errors and exception handling.

X