바이브코더를 위한 파이썬 기초 9편: 파일 저장과 encoding="utf-8"
파이썬 with open으로 한글 메모를 저장하고 읽는 법. 파일이 자동으로 닫히는 이유, Python 3.15의 UTF-8 기본 인코딩(PEP 686)과 그래도 encoding을 적어야 하는 이유를 정리했다.
프로그램을 끄면 변수에 담아 둔 값은 모두 사라진다. 할 일 목록이든 수집한 데이터든 남기려면 파일에 저장해야 한다. AI가 짜 주는 자동화 코드에도 with open(...) 줄이 자주 나온다. 이 글은 '바이브코더를 위한 파이썬 기초' 10편 중 9편으로, 한글 텍스트를 파일에 쓰고 다시 읽는 법과 with가 하는 일, 그리고 Python 3.15에서 바뀐 파일 기본 인코딩(UTF-8)과 그래도 encoding="utf-8"을 적어야 하는 이유를 정리한다. 예제는 Python 3.15 기준으로 설명하며 Python 3.14.2에서 실행해 결과를 확인했다(3.15 변경점은 공식 문서로 확인했다).
핵심 요약
- 프로그램이 끝나면 변수는 사라지지만 파일은 남는다.
with open(...) as f:는 블록이 끝나면 파일을 자동으로 닫아 준다.- Python 3.15부터 파일 기본 인코딩이 운영체제와 관계없이 UTF-8이 됐다(PEP 686, 따로 끄지 않은 경우).
- 그래도
encoding="utf-8"은 항상 직접 적는다. 3.14 이하 환경에서도 같은 결과가 나오게 하기 위해서다.
파일은 수첩이다
머릿속으로 기억한 건 자고 나면 잊지만, 수첩에 적어 둔 건 남는다. 변수가 머릿속이라면 파일은 수첩이다.
비유의 한계도 있다. 수첩은 덮는 걸 잊어도 내용이 그대로지만, 파일은 닫지 않으면 내용이 완전히 저장되지 않을 수 있다. 그래서 파이썬에는 파일을 알아서 닫아 주는 with 문법이 있다.
한글 메모 저장하고 다시 읽기
from pathlib import Path
path = Path("memo.txt")
path.write_text("오늘 할 일: 파이썬 공부\n", encoding="utf-8")
with open(path, encoding="utf-8") as f:
print(f.read().strip())
오늘 할 일: 파이썬 공부
한 줄씩 보면 이렇다.
from pathlib import Path: 파일 경로를 다루는Path도구를 불러온다.path.write_text(...): 파일에 글을 한 번에 쓴다. 파일이 없으면 만들고, 있으면 내용을 덮어쓴다.\n은 줄바꿈이다.with open(path, encoding="utf-8") as f:: 파일을 읽기용으로 열어f라는 이름을 붙인다. 들여쓴 블록이 끝나면 파일이 자동으로 닫힌다.f.read().strip(): 내용을 모두 읽고 앞뒤 공백·줄바꿈을 떼어 낸다.
AI 코드에는 write_text·read_text처럼 한 번에 쓰고 읽는 방식과 with open(...) 방식이 모두 나온다. 어느 쪽이든 encoding="utf-8"을 적는다.
파일은 터미널이 지금 열려 있는 폴더에 만들어진다(1편의 폴더 위치 이야기와 같다). 실행한 뒤 그 폴더에 memo.txt가 생겼는지 확인해 보자.
Python 3.15에서 바뀐 것: 기본 인코딩 UTF-8
인코딩은 글자를 파일에 0과 1로 저장하는 규칙이다. 쓸 때와 읽을 때 규칙이 다르면 한글이 알아볼 수 없는 글자로 깨져 보이거나, 읽는 도중 UnicodeDecodeError가 난다.
Python 3.15부터는 encoding을 적지 않아도, 따로 끄지 않는 한(PYTHONUTF8=0 등) 운영체제 설정과 관계없이 UTF-8을 기본으로 쓴다(Python 3.15 새 기능 문서, PEP 686). 그전까지 Windows에서는 지역 설정에 따른 기본 인코딩이 쓰여서, 한글 파일을 다른 환경과 주고받을 때 깨지는 일이 흔했다.
흔한 함정: 3.15니까 encoding은 안 써도 될까
기본값이 바뀌었으니 생략해도 될 것 같지만, 같은 코드를 3.14 이하가 설치된 Windows에서 돌리면 다른 인코딩으로 저장될 수 있다. 내 컴퓨터는 3.15여도, 코드를 받아 쓰는 동료나 서버는 다른 버전일 수 있다.
고치는 원칙은 간단하다. 파일을 열 때는 항상 encoding="utf-8"을 적는다. AI가 짠 코드에 open("data.txt")처럼 encoding이 빠져 있으면 "모든 open에 encoding="utf-8"을 넣어 줘"라고 요청하자.
AI 파일 코드를 실행하기 전에 볼 것
- 덮어쓰기인가, 이어쓰기인가?
open(path, "w")와write_text는 기존 내용을 지우고 새로 쓴다. 기존 내용 뒤에 붙이려면"a"(append) 모드를 쓴다. 중요한 파일을 다루는 코드라면 실행 전에 복사본을 만들어 둔다. - 어느 폴더에 쓰는가? 경로가 어디를 가리키는지 확인한다. 엉뚱한 폴더의 파일을 덮어쓰지 않도록.
with를 쓰는가?f = open(...)만 있고f.close()가 없다면with문법으로 바꿔 달라고 한다.encoding="utf-8"이 있는가? 한글을 다룬다면 특히 중요하다.
스스로 확인하기
- 3.15에서도
encoding="utf-8"을 적는 이유는? → 다른 버전·환경에서도 같은 결과를 내기 위해서. UTF-8이 기본값이 된 것은 3.15부터라 이전 버전에서는 결과가 다를 수 있다. with open(...) as f:를 쓰는 장점은? → 블록이 끝나면 파일이 자동으로 닫힌다. 빠르게 읽는 기능이 아니라 닫기를 보장하는 문법이다.
직접 해 보기
한글 메모 한 줄을 memo.txt에 저장하고 다시 읽어 출력해 보자. 그다음 메모장으로 memo.txt를 열었을 때도 한글이 깨지지 않으면 성공이다. 깨져 보이면 편집기가 UTF-8로 열고 있는지 확인한다.
이어쓰기도 연습해 보자.
from pathlib import Path
path = Path("memo.txt")
path.write_text("첫 번째 메모\n", encoding="utf-8")
with open(path, "a", encoding="utf-8") as f:
f.write("두 번째 메모\n")
print(path.read_text(encoding="utf-8"), end="")
첫 번째 메모
두 번째 메모
이전 편과 다음 편
- 이전 글: 8편: 오류 메시지는 마지막 줄부터 읽는다
- 다음 글: 10편: 작은 프로그램 만들기에서는 지금까지 배운 도구를 모아 할 일 목록 프로그램을 만든다.
시리즈 전체 목록은 10편 끝에 모아 두었다.