Python Basics for Vibe Coders, Part 9: Saving Files and encoding="utf-8"
Save and read files in Python using with open, why files close automatically, the UTF-8 default in Python 3.15 (PEP 686), and why to still set encoding.
When your program exits, every value stored in a variable is gone. Whether it's a to-do list or data you collected, if you want to keep it, you have to save it to a file. Automation code from an AI often includes a with open(...) line. This is Part 9 of the 10-part series "Python Basics for Vibe Coders," and it covers writing text with non-English characters to a file and reading it back, what with does, the new default file encoding in Python 3.15 (UTF-8), and why you should still write encoding="utf-8". The examples are written for Python 3.15, and I ran them in Python 3.14.2 to check the results (I checked the 3.15 changes against the official docs).
Key Takeaways
- Variables disappear when the program ends, but files stay.
with open(...) as f:closes the file for you when the block ends.- Starting with Python 3.15, the default file encoding is UTF-8 on every operating system (PEP 686, unless you turn it off).
- Still, always write
encoding="utf-8"yourself. That way you get the same result on Python 3.14 and earlier.
A file is a notebook
What you keep in your head fades after a night's sleep, but what you write in a notebook stays. If variables are your memory, a file is your notebook.
The analogy has a limit. A notebook keeps its contents even if you forget to close it, but a file may not be fully saved if you don't close it. That's why Python has the with syntax, which closes the file for you.
Saving a note and reading it back
The note below includes "é," a character outside plain ASCII, so it shows whether the encoding is handled correctly.
from pathlib import Path
path = Path("memo.txt")
path.write_text("Today's to-do: study Python at the café\n", encoding="utf-8")
with open(path, encoding="utf-8") as f:
print(f.read().strip())
Today's to-do: study Python at the café
Line by line:
from pathlib import Path: importsPath, a tool for working with file paths.path.write_text(...): writes text to the file in one go. If the file doesn't exist, it's created; if it does, its contents are overwritten.\nis a line break.with open(path, encoding="utf-8") as f:: opens the file for reading and names itf. When the indented block ends, the file is closed automatically.f.read().strip(): reads everything and removes spaces and line breaks from both ends.
AI code uses both styles: one-shot reading and writing like write_text and read_text, and with open(...). Either way, write encoding="utf-8".
The file is created in the folder your terminal currently has open (the same folder issue from Part 1). After running the code, check that memo.txt showed up in that folder.
What changed in Python 3.15: UTF-8 by default
An encoding is the rule for storing characters in a file as 0s and 1s. If you write with one rule and read with another, characters like "é" or Korean text come out as garbled, unreadable characters, or you get a UnicodeDecodeError partway through reading.
Starting with Python 3.15, even if you don't write encoding, Python uses UTF-8 by default regardless of your operating system settings, unless you turn it off (with PYTHONUTF8=0 or similar) (What's New in Python 3.15, PEP 686). Before that, Windows used a default encoding based on your region settings, so files with non-English text often got garbled when shared with other systems.
Common trap: it's 3.15, so can I skip encoding?
Since the default changed, it seems safe to leave it out. But if you run the same code on Windows with Python 3.14 or earlier, the file may be saved in a different encoding. Your computer might have 3.15, but a coworker or server that runs your code might have another version.
The fix is simple: always write encoding="utf-8" when you open a file. If AI code has something like open("data.txt") with no encoding, ask: "Add encoding="utf-8" to every open."
What to check before running AI file code
- Overwrite or append?
open(path, "w")andwrite_texterase the existing contents and write fresh. To add to the end of what's there, use"a"(append) mode. If the code touches an important file, make a copy before you run it. - Which folder is it writing to? Check where the path points, so you don't overwrite a file in the wrong folder.
- Does it use
with? If there's justf = open(...)and nof.close(), ask the AI to switch to thewithsyntax. - Is
encoding="utf-8"there? This matters most when you're handling non-English text.
Check yourself
- Why write
encoding="utf-8"even in 3.15? → To get the same result on other versions and setups. UTF-8 only became the default in 3.15, so earlier versions may behave differently. - What's the benefit of
with open(...) as f:? → The file closes automatically when the block ends. It's not a faster way to read; it's syntax that guarantees the file gets closed.
Try it yourself
Save a one-line note with a non-ASCII character in it (like "café") to memo.txt, then read it back and print it. If the character still looks right when you open memo.txt in Notepad, you've got it. If it looks garbled, check that your editor is opening the file as UTF-8.
Practice appending, too. The second note includes the Korean word "안녕" ("hi"), which only survives if the encoding is right.
from pathlib import Path
path = Path("memo.txt")
path.write_text("First note: café\n", encoding="utf-8")
with open(path, "a", encoding="utf-8") as f:
f.write("Second note: 안녕\n")
print(path.read_text(encoding="utf-8"), end="")
First note: café
Second note: 안녕
Previous and next
- Previous: Part 8: Read Error Messages from the Bottom Up
- Next: Part 10: Build a To-Do List with Everything You've Learned puts together everything you've learned so far to build a to-do list program.
The full series list is at the end of Part 10.