이번 편의 목표: UTF-8 텍스트를 저장하고 경로 기준을 명확하게 정합니다.

변수와 리스트는 프로그램이 실행되는 동안 자료를 기억합니다. 프로그램이 끝난 뒤에도 남기려면 파일에 저장해야 합니다. 첫 파일 실습은 새로운 폴더에서 진행합니다. 아래 코드는 `practice_output/memo.txt`를 만들며, 다시 실행하면 그 파일의 내용을 덮어씁니다.

경로를 문자열 조합에서 분리하기

Python
from pathlib import Path

folder = Path("practice_output")
folder.mkdir(parents=True, exist_ok=True)
path = folder / "memo.txt"

with path.open("w", encoding="utf-8") as file:
    file.write("커피: 4500원\n")
    file.write("점심: 8000원\n")

with path.open("a", encoding="utf-8") as file:
    file.write("교통: 1500원\n")

with path.open("r", encoding="utf-8") as file:
    for line in file:
        print(line.rstrip("\n"))

print(path.resolve())

`Path`는 파일과 폴더의 경로를 다루는 객체입니다. `/`로 경로를 연결하면 Windows와 macOS·Linux의 경로 구분자 차이를 직접 처리할 필요가 줄어듭니다. `mkdir()`는 폴더를 만들고, `exist_ok=True`는 같은 폴더가 이미 있는 경우를 허용합니다.

`"w"`는 쓰기 모드이며 기존 내용을 지우고 새로 씁니다. `"a"`는 끝에 덧붙이는 모드입니다. `"r"`은 읽기 모드이고 파일이 없으면 `FileNotFoundError`가 납니다. 기존 파일을 덮어쓰지 않고 새 파일만 만들려면 `"x"` 모드를 사용할 수 있습니다.

with가 관리하는 실행 범위

`with` 블록을 나가면 파일이 닫힙니다. 중간에 예외가 발생해도 정리를 수행합니다. 파일을 열어 두고 닫는 줄을 잊는 일을 줄여 줍니다. 다만 파일 닫기가 모든 저장 실패를 막아 준다는 뜻은 아닙니다. 권한이나 디스크 문제는 별도로 처리해야 합니다.

텍스트에는 인코딩을 명시합니다. 이 연재에서는 기본적으로 `encoding="utf-8"`을 사용합니다. CSV를 엑셀에서 직접 여는 실습에서는 호환을 위해 18편에서 `utf-8-sig`도 다룹니다. 인코딩과 줄바꿈, 쉼표 구분은 서로 다른 문제입니다.

상대 경로는 무엇을 기준으로 할까

`Path("practice_output")`의 기준은 보통 현재 작업 디렉터리입니다. 스크립트 파일이 있는 곳과 항상 같지는 않습니다. 다른 폴더에서 실행하면 출력 폴더도 다른 곳에 만들어질 수 있습니다. `Path.cwd()`로 현재 기준을 확인하고, `path.resolve()`로 실제 절대 경로를 확인할 수 있습니다.

스크립트 옆을 기준으로 삼으려면 `.py` 파일에서 `Path(__file__).resolve().parent`를 사용합니다. 대화형 모드나 노트북에는 `__file__`이 없을 수 있습니다. 마지막 지출 기록기에서는 기본 자료 경로를 스크립트 옆으로 정하겠습니다.

직접 해 보기

`practice_output/note.txt`를 처음 만들 때만 한 줄을 쓰고, 이미 있으면 기존 내용을 읽으세요. 새 파일 전용 `x` 모드로 덮어쓰기를 방지하세요.

해설

Python
from pathlib import Path

path = Path("practice_output") / "note.txt"
path.parent.mkdir(parents=True, exist_ok=True)
try:
    with path.open("x", encoding="utf-8") as file:
        file.write("파이썬 파일 실습\n")
except FileExistsError:
    print("기존 메모를 읽습니다.")
print(path.read_text(encoding="utf-8"))

두 번 실행해도 첫 메모를 덮어쓰지 않습니다. 파일을 쓰는 코드에서는 실행 후 생기는 결과와 재실행했을 때의 동작을 함께 설명할 수 있어야 합니다.