남잭슨의 개발 블로그
pip install은 성공했는데 ModuleNotFoundError가 계속된다면, 패키지를 설치한 Python과 프로그램을 실행하는 Python의 경로부터 비교하세요. 버전 번호가 같아도 서로 다른 가상환경이면 설치된 패키지는 다를 수 있습니다.
이 글에서는 같은 Python으로 가상환경 두 개를 만들고, 한쪽에만 패키지를 설치해 오류를 재현했습니다. 실제 서비스나 기존 프로젝트는 사용하지 않았습니다. 모든 모듈 오류의 원인을 설명하기보다, “분명 설치했는데 실행할 때만 없다”는 상황을 좁히는 방법에 집중합니다.

같은 Python이라도 환경별 설치 패키지가 다를 수 있음을 표현한 AI 생성 설명용 일러스트입니다. 실습 결과는 본문의 표와 로그를 참고하세요.
버전은 같았지만, 패키지가 들어 있는 환경은 달랐다
2026년 10월 27일 macOS의 Python 3.14.4에서 실습했습니다. 인터넷에서 패키지를 받는 대신 blog_probe_demo라는 작은 예제 모듈을 로컬 wheel로 만들어 사용했습니다. import에 성공하면 module-loaded라는 문자열을 읽을 수 있도록 구성했습니다.
가상환경 A에만 설치한 다음 A와 B에서 똑같은 import를 실행했습니다. Python 버전은 두 환경 모두 같았고 pip도 26.1이었습니다.
| 확인한 환경 | 설치 상태 | 실제 결과 |
|---|---|---|
| A: env-installed | 예제 모듈 설치됨 | module-loaded |
| B: env-running | 설치 안 됨 | ModuleNotFoundError |
| B에 같은 wheel 설치 후 | 설치됨 | module-loaded |
B에서 확인한 오류의 마지막 줄은 다음과 같습니다. 실제 실행 결과를 텍스트로 옮긴 것이며, 화면을 합성한 이미지는 아닙니다.
ModuleNotFoundError: No module named 'blog_probe_demo'
패키지 설치가 실패한 것이 아니라 설치한 곳과 실행한 곳이 달랐습니다. 이 실습에서는 실행 환경 B에 같은 패키지를 설치한 뒤 오류가 사라졌습니다. 네트워크 장애나 패키지 버전 충돌은 포함하지 않은 조건입니다.
1. 오류가 나는 프로그램 안에서 Python 경로 확인하기
터미널에서 먼저 버전을 확인하는 것보다, 오류가 발생하는 실행 방식 그대로 다음 코드를 실행해 보세요. import 오류가 나는 코드 위에 잠깐 넣어도 됩니다.
import sys
print(sys.executable)
print(sys.version)
print(sys.prefix)
sys.executable은 현재 실행 중인 Python 실행 파일의 경로를 알려 줍니다. 이 경로가 설치할 대상을 고르는 기준입니다. Python의 sys.executable 문서
이번 실습에서는 아래처럼 환경 이름이 달랐습니다. LAB_ROOT는 실습 폴더의 실제 절대 경로를 가린 표기입니다.
A: LAB_ROOT/python-import/env-installed/bin/python
B: LAB_ROOT/python-import/env-running/bin/python
이 실습처럼 env-installed와 env-running이라는 서로 다른 가상환경을 가리킨다면, 버전이 같아도 설치 공간이 다릅니다. 실행 파일 이름만 다른 경우까지 다른 환경으로 단정하지 말고, 현재 환경의 기준 디렉터리인 sys.prefix도 함께 비교하세요. 가상환경에서 이 값이 가리키는 위치는 Python venv 공식 설명에서 확인할 수 있습니다. VS Code 실행 버튼, 별도 터미널, 노트북 셀을 번갈아 사용했다면 오류가 나는 쪽에서 확인해야 합니다.

격리 실습의 진행을 정리한 설명용 도식입니다. 실제 터미널 스크린샷은 아니며, 두 환경의 Python 버전은 같았습니다.
2. 같은 Python으로 pip를 실행하기
다음 예시는 현재 터미널의 python이 앞에서 확인한 실행 파일을 가리킨다는 조건입니다. 사용하는 명령이 python3라면 세 줄 모두 같은 명령으로 바꿉니다. 터미널에서 실행하며, Python의 >>> 입력창에 넣는 명령이 아닙니다.
python -c "import sys; print(sys.executable)"
python -m pip --version
python -m pip show requests
requests는 명령 형식을 보여 주는 예시입니다. 실제로 확인하려는 배포 패키지 이름으로 바꾸세요. python -m pip처럼 호출하면 선택한 Python으로 pip 모듈을 실행합니다. pip 공식 사용 안내도 여러 Python이 설치된 경우 이 방식으로 대상을 지정합니다.
세 번째 명령에서 패키지를 찾지 못했고, 프로젝트에 필요한 패키지가 맞다면 그 프로젝트의 가상환경에 설치합니다. 아래는 프로젝트 폴더에 .venv가 이미 존재하고, 그 폴더에서 실행하는 macOS·Linux 예시입니다. 가상환경 이름이나 위치가 다르면 앞에서 확인한 실행 파일 경로를 사용합니다.
.venv/bin/python -m pip install requests
.venv/bin/python -c "import requests; print(requests.__file__)"
첫 줄의 대상은 임의의 전역 Python이 아니라 실제 프로그램이 사용할 환경이어야 합니다. 이미 의존성 관리 파일이나 전용 도구를 쓰는 프로젝트라면 해당 방식으로 설치하고, 실행 파일 경로를 다시 비교하세요. 가상환경을 사용하는 설치 흐름은 Python Packaging의 가상환경 안내에서 확인할 수 있습니다.
정확한 가상환경의 실행 파일을 지정하면 별도로 활성화하지 않고도 그 환경의 Python을 사용할 수 있습니다. Windows PowerShell에서 프로젝트의 기존 .venv를 쓰는 경우에는 아래처럼 경로가 달라집니다. 이 두 줄은 문서 기반 예시이며, 앞의 재현 실습은 macOS에서 수행했습니다. venv의 실행 파일과 활성화 안내
.\.venv\Scripts\python.exe -m pip install requests
.\.venv\Scripts\python.exe -c "import requests; print(requests.__file__)"
VS Code에서만 실패하면 실행 버튼 쪽을 확인한다
터미널에서는 import가 되는데 VS Code Python 확장의 Run Python File in Terminal에서 실패한다면 명령 팔레트의 Python: Select Interpreter로 프로젝트 환경을 선택합니다. 그다음 같은 실행 명령으로 sys.executable을 다시 출력해 경로가 맞는지 확인하세요. 다른 실행 확장이나 별도 task는 자체 설정을 사용할 수 있습니다. VS Code Python 실행 안내
VS Code 공식 문서에 따르면 선택한 환경은 코드 실행과 디버깅 등에 사용됩니다. 다만 디버깅 설정의 launch.json에 별도 python 경로를 지정했다면 이를 따를 수 있습니다. 실행과 디버깅에서 결과가 다를 때는 이 설정도 살펴봅니다. 이 부분은 문서 기반 안내이며, 이번 실습에서 VS Code UI를 조작해 재현한 것은 아닙니다. VS Code의 환경 선택 안내
Jupyter에서도 터미널의 Python과 현재 커널을 구분해야 합니다. 노트북 셀에서 import sys; print(sys.executable)을 실행해 확인하세요. Python Packaging 설치 안내 역시 현재 노트북과 같은 Python을 사용하도록 실행 파일 경로를 기준으로 삼습니다.
환경이 같은데도 안 되면 오류에 나온 이름을 다시 본다
| 관찰한 결과 | 다음 확인 |
|---|---|
| 실행 Python과 설치 Python의 경로가 다름 | 실제로 사용할 환경을 정하고, 그 환경의 의존성을 설치 |
| 경로는 같은데 pip에서 배포 패키지를 찾지 못함 | 프로젝트의 의존성 선언과 올바른 배포 이름을 확인 |
| 배포 패키지는 있는데 import 이름이 다름 | 해당 라이브러리의 공식 설치·import 예제와 대조 |
| 오류에 나온 모듈 이름이 내가 설치한 것과 다름 | 전체 traceback에서 어느 import가 실패했는지 확인 |
| 터미널은 성공하고 IDE·노트북만 실패 | 실패하는 실행 방식에서 sys.executable 재확인 |
설치할 때 쓰는 배포 이름과 코드에서 import하는 이름은 항상 같지는 않습니다. 예를 들어 Pillow는 PIL로 import합니다. 따라서 오류에 나온 이름을 그대로 검색해 아무 패키지나 설치하기보다 해당 라이브러리의 문서를 확인해야 합니다. 배포 패키지와 import 패키지의 차이
해결 여부는 “설치 완료” 메시지보다 원래 실패했던 실행 방식에서 같은 import가 성공하는지로 판단하세요. 이번 실습처럼 환경 경로를 한 번 비교하면, 패키지를 반복 설치하기 전에 원인을 한 단계 좁힐 수 있습니다.
'개발일지' 카테고리의 다른 글
| EC2를 중지했는데 요금이 나올 때: EBS·탄력적 IP 확인 (0) | 2026.10.30 |
|---|---|
| localStorage 데이터가 다른 기기에서 안 보이는 이유: 주소·브라우저·저장 위치 (0) | 2026.10.30 |
| React·Vite 배포 후 새로고침 404: SPA fallback과 base 구분하기 (0) | 2026.10.29 |
| Docker Desktop에서 호스트 DB 연결 안 될 때: localhost 확인 (0) | 2026.10.28 |
| HTTPS 사이트에서 HTTP API 호출이 막힐 때: Mixed Content 해결 순서 (0) | 2026.10.28 |
