__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__) 처리합니다.

 

이렇게 작성하니 개발, 배포과정의 경로 문제가 해결되었습니다. 😀

 

이상으로 설명을 마칩니다.

감사합니다. 

댓글

이 블로그의 인기 게시물

Qt Designer 설치하기

파이썬을 활용한 PID 제어기 GUI 구현

PyQt5 기반 동영상 플레이어앱 만들기