__file__ 경로 얻을때 주의사항
파일 경로 얻기
최근 Python으로 작성된 코드 중, 파일 경로를 얻는 코드부분에 문제가 있었습니다.
저는 평소 경로를 얻을때 코드를 아래와 같이 작성합니다.
import os curr_path = os.path.abspath(__file__) curr_dir = os.path.dirname(curr_path) file_path = os.path.join(curr_dir, 'Salary_dataset.csv')
현재 경로가 C:\ML 이라면, 출력은 아래와 같습니다.
c:\ML\Salary_dataset.csv
os모듈의 getcwd() 함수를 떠올렸다면 좋은 생각은 아닙니다.
만약 터미널에서 아래 경로의 파일을 실행하면,
cd C:\home python home\user\test.py
아래와 같이,
getcwd() 는 현재 터미널의 경로를,
__file__ 은 스크립트(*.py) 의 경로를 출력합니다.
C:\home (getcwd, 현재 작업경로) C:\home\user (__file__ *.py 파일이 있는 경로)
즉, getcwd() 는 현재 스크립트의 경로를 제대로 가져오지 못하는 경우가 있습니다.
따라서 __file__을 별 문제없이 사용해 왔는데 최근 Pyinstaller에서 문제가 발생하였습니다.
Pyinstaller에서 __file__
위 코드로 경로를 얻어와 이미지를 출력하는데 개발시에는 문제가 없다가 배포시에 문제가 발생하였습니다.
Pyinstaller로 만든 배포파일(*.exe)에서 이미지 경로를 얻어오지 못하네요.
__file__ 관련 문제원인은 아래와 같습니다.
- Python 스크립트를 실행할 때는 __file__ 이 "현재 .py 파일이 있는 경로"
- PyInstaller 로 실행파일(.exe) 을 만들면, .py 파일들이 전부 압축(*.exe 내부)
따라서 실행 시점에는 더 이상 원래 .py 파일이 물리적(*.exe로 압축)으로
존재하지 않으므로 __file__ 이 잘못된 경로나 아예 동작 안하는
현상입니다.
대처방법
원인은 찾았지만 개발시 *.py 스크립트 실행(컴파일타임)과 Pyinstaller 실행(런타임)을 따로 처리해야하는 과정이 남았습니다.
왜냐하면 __file__ 사용시 *.py파일이 배포판(*.exe 등) 에서는 압축되어 존재하지 않고, 평소 개발시에는 존재하기 때문입니다. (컴파일 타임 구분 불가)
위 문제는 경로찾기를 아래와 같이 구분해 처리합니다.
import os import sys if getattr(sys, 'frozen', False): # exe 실행 중 base_path = os.path.dirname(sys.executable) # 실행파일(.exe)이 있는 폴더 else: # 개발 환경 (py로 실행) base_path = os.path.dirname(os.path.abspath(__file__)) # images 경로 img_path = os.path.join(base_path, "images", "my_image.png") # CSV 경로 csv_path = os.path.join(base_path, "Salary_dataset.csv") print(img_path) print(csv_path)
getattr(sys, 'frozen', False) 함수는 sys 객체에 frozen 속성이 있으면 그 값을 반환하고, 없으면 False를 반환합니다.
여기서 'frozen' 은 PyInstaller 같은 번들러로 만든 ‘frozen’(묶여 실행되는) 앱을 감지하는 역할이므로 런타임에 실행파일 여부를 감지합니다.
실행파일인 경우 sys.executable 로 경로를 얻어처리하고 아니면 기존과 같이(__file__) 처리합니다.
이렇게 작성하니 개발, 배포과정의 경로 문제가 해결되었습니다. 😀
이상으로 설명을 마칩니다.
감사합니다.
댓글
댓글 쓰기