Summary

  • 상대 경로는 터미널 실행 위치(CWD)에 따라 달라져 FileNotFoundError를 일으킨다
  • Path(__file__).resolve().parent 패턴은 파일 자체 위치를 기준으로 삼아 어디서 실행하든 흔들리지 않는다
  • 경로 결합은 슬래시(/) 연산자로 하며 OS 구분은 pathlib가 알아서 처리한다

문제: 상대 경로의 배신

리소스 파일을 불러올 때 상대 경로를 쓰면 터미널 실행 위치에 따라 경로가 달라진다.

# 위험한 방식 — 터미널 실행 위치에 따라 경로가 달라짐
config_path = "./config/settings.yaml"

이 코드는 main.py가 있는 폴더에서 실행하면 작동하지만, 다른 경로에서 실행하면 ./를 현재 작업 위치(CWD)로 인식해 파일을 찾지 못한다.


해결: pathlib의 황금 패턴

파일 자체의 위치를 기준으로 경로를 잡으면 실행 위치와 무관하게 안전하다.

from pathlib import Path
 
BASE_DIR = Path(__file__).resolve().parent
PROMPT_DIR = BASE_DIR / "prompts"

이 한 줄은 세 단계로 나뉜다.

코드결과설명
Path(__file__)./src/main.py현재 파일 경로(상대 경로일 수 있음)
.resolve()C:\Project\src\main.py디스크상의 절대 경로로 변환
.parentC:\Project\src파일명을 떼고 부모 폴더만 남김
  • Path(__file__): __file__은 현재 실행 중인 파일의 경로를 담은 내장 변수다. Path()로 다루기 쉬운 객체로 만든다.
  • .resolve(): 경로를 절대 경로로 확정한다. 실행 환경에 따라 상대 경로로 인식될 수 있는 __file__을 디스크상의 실제 전체 주소로 고정하며, 심볼릭 링크 문제도 해결한다.
  • .parent: 필요한 것은 파일이 아니라 기준 폴더이므로, 파일명을 떼어내고 부모 디렉토리만 남긴다.

활용

BASE_DIR을 기준으로 프로젝트 내 어떤 파일이든 안전하게 가리킬 수 있다. OS별 경로 구분(\ vs /)은 pathlib가 알아서 처리한다.

from pathlib import Path
 
BASE_DIR = Path(__file__).resolve().parent
 
# 슬래시 연산자로 경로 결합
IMAGE_DIR = BASE_DIR / "data" / "images"
CONFIG_FILE = BASE_DIR / "config.json"
 
if not CONFIG_FILE.exists():
    print(f"설정 파일을 찾을 수 없습니다: {CONFIG_FILE}")
else:
    print(f"설정 파일 로드 완료: {CONFIG_FILE}")

리소스 파일을 다룰 때는 os.path나 단순 문자열 경로 대신 pathlib.resolve().parent 패턴을 쓰는 것이 견고한 코드의 첫걸음이다.


Reference