바이브코더를 위한 파이썬 기초

바이브코더를 위한 파이썬 기초 9편: 파일 저장과 encoding="utf-8"

파이썬 with open으로 한글 메모를 저장하고 읽는 법. 파일이 자동으로 닫히는 이유, Python 3.15의 UTF-8 기본 인코딩(PEP 686)과 그래도 encoding을 적어야 하는 이유를 정리했다.

바이브코더를 위한 파이썬 기초 9편: 파일 저장과 encoding="utf-8"

프로그램을 끄면 변수에 담아 둔 값은 모두 사라진다. 할 일 목록이든 수집한 데이터든 남기려면 파일에 저장해야 한다. 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"이 있는가? 한글을 다룬다면 특히 중요하다.

스스로 확인하기

  1. 3.15에서도 encoding="utf-8"을 적는 이유는? → 다른 버전·환경에서도 같은 결과를 내기 위해서. UTF-8이 기본값이 된 것은 3.15부터라 이전 버전에서는 결과가 다를 수 있다.
  2. 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="")
첫 번째 메모
두 번째 메모

이전 편과 다음 편

시리즈 전체 목록은 10편 끝에 모아 두었다.

목록으로