sys, pathlib, sys.path 사용하기

Tasker_Jang·2026년 3월 20일

1. 왜 이걸 알아야 하는가

파이썬 코드를 프로젝트 루트에서 실행했을 때 이런 에러를 만난 적 있을 것입니다.

ModuleNotFoundError: No module named 'my_module'

분명히 같은 폴더에 파일이 있는데 왜 못 찾는 걸까요? 이걸 이해하려면 Python이 import를 처리하는 방식을 알아야 합니다.


2. import가 동작하는 원리

Python은 import를 만나면 sys.path 라는 리스트를 참조합니다. sys.path는 Python이 모듈을 탐색할 폴더 경로들을 순서대로 담아둔 리스트로, 위에서부터 차례대로 뒤져서 해당 모듈을 찾습니다.

import sys
print(sys.path)

# 출력 예시
[
  '/Users/me/myproject',                # 현재 실행 위치
  '/usr/lib/python3.11',                # Python 표준 라이브러리
  '/usr/lib/python3.11/site-packages',  # pip/uv로 설치한 패키지들
  ...
]

찾으면 즉시 import하고, 리스트 끝까지 없으면 ModuleNotFoundError를 던집니다.

import my_module 실행
        │
        ├─ 0번: /Users/me/myproject/ 에서 탐색  → 없음
        ├─ 1번: /usr/lib/python3.11/ 에서 탐색  → 없음
        ├─ 2번: site-packages/ 에서 탐색        → 없음
        │
        └─ ModuleNotFoundError !

myproject/utils/sys.path에 없으니까 거기 있는 파일을 못 찾는 것입니다. Python은 실행 시 스크립트 위치, 표준 라이브러리, site-packages만 자동으로 sys.path에 등록하기 때문입니다. myproject/utils/처럼 프로젝트 내부의 임의 폴더는 직접 추가해주지 않으면 탐색 대상이 되지 않습니다.


3. sys 모듈이란?

sys는 Python 표준 라이브러리 중 하나로, Python 인터프리터 자체와 관련된 정보와 기능에 접근할 수 있게 해줍니다.

import sys

sys.path     # 모듈 탐색 경로 리스트
sys.version  # Python 버전
sys.argv     # 실행 시 전달된 인자 리스트
sys.exit()   # 프로그램 종료

이 중에서 sys.path가 오늘의 핵심입니다.


4. sys.path.insert(0, ...) 로 문제 해결하기

탐색 경로에 우리 폴더를 직접 추가하면 됩니다.

import sys
sys.path.insert(0, 'myproject/utils/')

import my_module  # 이제 찾을 수 있음!

여기서 insert(0, ...)0"리스트 맨 앞에 넣어라" 라는 인덱스 번호입니다. myproject/utils/가 0번이 "되도록" 직접 집어넣는 것입니다.

sys.path.insert(0, '...')  # 맨 앞 → 제일 먼저 탐색
sys.path.append('...')     # 맨 뒤 → 제일 나중에 탐색

💡 append()로 뒤에 붙여도 기술적으로는 동작하지만, 맨 앞에 넣어야 다른 경로보다 먼저 탐색되어 이름 충돌 가능성을 없앨 수 있습니다.


5. pathlibPath란?

그런데 위 코드에는 한 가지 문제가 있습니다. 경로를 하드코딩했다는 것입니다.

sys.path.insert(0, 'myproject/utils/')  # 어디서 실행하느냐에 따라 달라짐!

프로젝트 루트가 아닌 다른 위치에서 실행하면 경로가 틀려버립니다. 이걸 해결해주는 것이 pathlib입니다.

pathlib은 Python 표준 라이브러리로, 파일 경로를 문자열 대신 객체로 다룰 수 있게 해줍니다.

# 옛날 방식 (os 모듈)
import os
print(os.path.dirname(os.path.abspath(__file__)))

# 요즘 방식 (pathlib)
from pathlib import Path
print(Path(__file__).parent)

결과는 같지만 pathlib이 훨씬 직관적입니다.


6. __file__ — 자기 자신의 경로

__file__은 Python이 자동으로 제공하는 특수 변수로, 현재 실행 중인 파일의 경로를 담고 있습니다.

# main.py 안에서
print(__file__)
# → '/Users/me/myproject/utils/main.py'

어디서 실행하든 항상 자기 자신의 경로를 가리킵니다.


7. .parent — 부모 폴더 가져오기

Path 객체의 .parent 속성은 해당 경로의 한 단계 위 폴더를 반환합니다.

from pathlib import Path

p = Path('/Users/me/myproject/utils/main.py')

p.parent         # → PosixPath('/Users/me/myproject/utils')
p.parent.parent  # → PosixPath('/Users/me/myproject')

Path 객체는 / 연산자로 경로를 이어붙일 수도 있습니다. Path 객체에 / 연산자로 경로를 이어붙일 때 오른쪽은 반드시 문자열이어야 합니다. 큰따옴표가 없으면 Python이 sample_docs를 변수 이름으로 읽어버려서 NameError가 납니다.

base = Path('/Users/me/myproject')
base / 'utils' / 'sample_docs'
# → PosixPath('/Users/me/myproject/utils/sample_docs')

문자열이었으면 base + '/utils/' + 'sample_docs' 이렇게 써야 했을 텐데, 훨씬 직관적입니다.


8. 완성된 패턴 — 어디서 실행해도 안전한 import

이제 모든 조각을 합칩니다.

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))

한 줄씩 풀어보면 이렇습니다.

Path(__file__)          # main.py 자기 자신의 경로
                        # → PosixPath('/Users/me/myproject/utils/main.py')

Path(__file__).parent   # 그 파일이 있는 폴더
                        # → PosixPath('/Users/me/myproject/utils')

str(...)                # sys.path는 문자열 리스트라서 변환 필요
                        # → '/Users/me/myproject/utils'

sys.path.insert(0, ...) # sys.path 맨 앞에 삽입

💡 __file__은 항상 자기 자신의 절대 경로를 담고 있기 때문에, 프로젝트 루트에서 실행하든 어느 폴더에서 실행하든 .parent는 항상 myproject/utils/를 정확하게 가리킵니다. 실행 위치에 흔들리지 않는 안정적인 import가 완성되는 것입니다.


9. 실전 활용 예시

import sys
from pathlib import Path

# ① 내 폴더를 탐색 경로 맨 앞에 추가 (선행 조건)
sys.path.insert(0, str(Path(__file__).parent))

# ② 이제 같은 폴더의 파일들을 import 가능
import my_module_a
import my_module_b
import my_module_c

sys.path.insert()가 선행 조건이라는 점이 핵심입니다. 이 한 줄이 없으면 바로 아래의 import 세 줄이 모두 실패합니다. 반드시 import 전에 경로를 등록해두어야 합니다.

---

## 10. `pathlib` 더 적극적으로 활용하기

`pathlib`의 진가는 경로 조합이 많아질수록 빛납니다.

```python
from pathlib import Path

BASE_DIR    = Path(__file__).parent      # 현재 파일의 폴더
SAMPLE_DIR  = BASE_DIR / "sample_docs"  # / 연산자로 경로 이어붙이기
OUTPUT_DIR  = BASE_DIR / "output"

OUTPUT_DIR.mkdir(exist_ok=True)          # 폴더 없으면 자동 생성

os 모듈 방식과 비교하면 차이가 명확합니다.

# os 방식
import os
base   = os.path.dirname(os.path.abspath(__file__))
sample = os.path.join(base, 'sample_docs')
os.makedirs(sample, exist_ok=True)

# pathlib 방식
from pathlib import Path
base   = Path(__file__).parent
sample = base / 'sample_docs'
sample.mkdir(exist_ok=True)

11. 핵심 정리

개념한 줄 설명
sysPython 인터프리터 관련 정보·기능 모듈
sys.pathimport 탐색 경로 리스트 (위→아래 순서대로)
sys.path.insert(0, ...)탐색 경로 맨 앞에 경로 추가
pathlib파일 경로를 객체로 다루는 표준 라이브러리
Path경로 객체 클래스
__file__현재 실행 중인 파일의 경로 (특수 변수)
.parent한 단계 위 폴더 반환
/ 연산자Path 객체끼리 경로 이어붙이기

한 줄 요약: sys.path.insert(0, str(Path(__file__).parent)) 는 "어느 폴더에서 실행하든 항상 내 옆에 있는 모듈을 찾을 수 있게" 보장하는 패턴입니다.

profile
ML Engineer 🧠 | AI 모델 개발과 최적화 경험을 기록하며 성장하는 개발자 🚀 The light that burns twice as bright burns half as long ✨

0개의 댓글