Python Basics for Vibe Coders

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.

Python Basics for Vibe Coders, Part 9: Saving Files and encoding="utf-8"

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).

Illustration on a dark background of glowing particles flowing from a hazy cloud into an open notebook, with an orange folder beside it

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: imports Path, 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. \n is a line break.
  • with open(path, encoding="utf-8") as f:: opens the file for reading and names it f. 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") and write_text erase 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 just f = open(...) and no f.close(), ask the AI to switch to the with syntax.
  • Is encoding="utf-8" there? This matters most when you're handling non-English text.

Check yourself

  1. 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.
  2. 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

The full series list is at the end of Part 10.

Back to list