- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Python 스크립트를 다른 사람에게 전달할 때마다 "Python 설치하세요", "pip로 의존성 설치하세요"라고 안내하는 것은 비효율적입니다. PyInstaller를 사용하면 .py 파일을 독립 실행 가능한 .exe로 변환하여, Python이 설치되지 않은 환경에서도 바로 실행할 수 있습니다. 이 글에서는 PyInstaller 기본 사용법부터 배포 시 자주 발생하는 리소스 경로 문제, 모듈 누락 에러 해결까지 실무에서 필요한 핵심 내용만 다룹니다.
| PyInstaller로 파이썬 스크립트를 exe 실행 파일로 변환하는 완벽 가이드 |
1. PyInstaller 설치 및 기본 빌드
PyInstaller는 Python 스크립트와 의존성 라이브러리를 하나로 묶어 실행 파일을 생성하는 도구입니다. 설치는 pip 한 줄로 끝납니다.
pip install pyinstaller
기본 빌드 명령은 다음과 같습니다.
pyinstaller my_script.py
실행하면 다음 3가지 산출물이 생성됩니다.
- dist/: 최종 실행 파일이 위치하는 폴더. 배포 시 이 폴더 내용을 전달합니다.
- build/: 중간 빌드 파일. 삭제해도 무방합니다.
- .spec: 빌드 설정 파일. 리소스 포함, 숨겨진 모듈 추가 등 고급 설정 시 수정합니다.
기본 빌드는 여러 파일로 구성된 디렉토리 형태로 출력됩니다. 단일 실행 파일로 만들려면 --onefile(-F) 옵션을 사용하십시오.
pyinstaller --onefile my_script.py
GUI 프로그램의 경우 콘솔 창이 함께 뜨는 것을 방지하려면 --noconsole(-w) 옵션을 추가합니다.
pyinstaller --onefile --noconsole my_script.py
단축 옵션으로는 -F -w를 사용할 수 있습니다.
2. 리소스 경로 처리 문제 해결
PyInstaller로 빌드한 .exe는 실행 시 임시 폴더(sys._MEIPASS)에 압축 해제되어 동작합니다. 따라서 .py 실행 시와 .exe 실행 시 리소스 파일 경로가 달라지며, 이를 처리하지 않으면 FileNotFoundError가 발생합니다.
다음 함수를 사용하여 실행 환경에 따라 올바른 경로를 반환하도록 처리하십시오.
import sys
import os
def get_base_path():
if getattr(sys, 'frozen', False):
# exe 상태일 경우
return sys._MEIPASS
else:
# 스크립트 상태일 경우
return os.path.dirname(__file__)
CONFIG_PATH = os.path.join(get_base_path(), 'config', 'config.txt')
getattr(sys, 'frozen', False)는 현재 실행 파일이 PyInstaller로 빌드된 .exe인지 판별하는 표준 방법입니다. 이 코드를 적용하면 개발 환경(.py)과 배포 환경(.exe) 모두에서 정상적으로 리소스를 로드할 수 있습니다.
만약 설정 파일, 이미지, 사운드 등 외부 리소스를 .exe에 포함시키려면 .spec 파일의 datas 항목을 수정하거나, 배포 시 exe와 함께 해당 폴더를 압축하여 전달하는 방식을 권장합니다.
# .spec 파일 내부 예시
a = Analysis(
['my_script.py'],
datas=[('./config', 'config'), ('./sounds', 'sounds')],
hiddenimports=[],
...
)
3. 모듈 누락 에러(ModuleNotFoundError) 해결
PyInstaller는 정적 분석으로 import 구문을 추적하지만, 동적 import(런타임에 결정되는 모듈)는 감지하지 못합니다. 이 경우 빌드는 성공하지만 실행 시 ModuleNotFoundError가 발생합니다.
해결 방법은 다음 3가지입니다.
- CLI 옵션 사용: --hidden-import 옵션으로 누락된 모듈을 명시합니다.
pyinstaller --onefile --hidden-import=PIL._tkinter_finder my_script.py
- .spec 파일 수정: hiddenimports 리스트에 모듈명을 추가합니다.
a = Analysis(
['my_script.py'],
hiddenimports=['PIL._tkinter_finder', 'sklearn.utils._typedefs'],
...
)
- Hook 파일 작성: 특정 패키지의 서브모듈을 전부 포함해야 할 경우, hook-패키지명.py 파일을 작성합니다.
# hook-sklearn.py
from PyInstaller.utils.hooks import collect_submodules
hiddenimports = collect_submodules('sklearn')
디버깅 시에는 --noconsole 옵션을 제거하여 콘솔 출력을 확인하거나, 디렉토리 모드로 빌드하여 dist 폴더 내부를 직접 확인하는 방법을 권장합니다.
4. 실행 파일 용량 최적화 및 배포 전략
PyInstaller는 의존성 라이브러리를 모두 포함하기 때문에 실행 파일 크기가 수십 MB에 달할 수 있습니다. 용량을 줄이려면 다음 방법을 사용하십시오.
- 깨끗한 가상환경에서 빌드: 프로젝트에 필요한 패키지만 설치한 가상환경(venv)에서 빌드하면 불필요한 라이브러리가 포함되지 않습니다.
- UPX 압축: PyInstaller는 기본적으로 UPX 압축을 지원합니다. --upx-dir 옵션으로 UPX 경로를 지정하면 추가 압축이 가능합니다.
- 대체 도구 검토: Nuitka, cx_Freeze 등은 PyInstaller보다 작은 실행 파일을 생성할 수 있습니다.
배포 시에는 다음 구조를 권장합니다.
MyApp_Package/ ├─ main.exe ├─ config/ │ └─ config.txt ├─ sounds/ └─ logs/
플랫폼 호환성 주의사항: PyInstaller로 빌드한 실행 파일은 빌드한 플랫폼과 동일한 환경에서만 실행됩니다. Windows에서 빌드한 .exe는 macOS나 Linux에서 실행되지 않으며, 32비트/64비트, Python 버전도 일치해야 합니다. 대상 환경에서 직접 빌드하거나, Docker 등을 활용한 크로스 빌드 환경을 구성하십시오.
요약 및 Action Item
PyInstaller는 Python 스크립트를 독립 실행 파일로 변환하는 가장 간단한 도구입니다. --onefile로 단일 파일을 생성하고, --noconsole로 GUI 프로그램의 콘솔을 숨기며, sys._MEIPASS를 활용해 리소스 경로를 처리하고, --hidden-import로 동적 모듈 누락을 해결하면 대부분의 배포 문제를 해결할 수 있습니다. 지금 당장 가상환경을 생성하고, 필요한 패키지만 설치한 뒤 pyinstaller --onefile --noconsole your_script.py 명령을 실행하여 첫 번째 실행 파일을 만들어보십시오.
#함께 읽으면 좋은 글
Python pip install 속도 느림 해결 방법: 국내 미러 서버 설정 완벽 가이드 : 바로보기
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기