TIL 37. python이 모듈을 찾는 방법

wonseok2877·2021년 6월 11일
0

python

목록 보기
10/10
post-thumbnail

python이 모듈을 import할 때 파일을 찾는 과정을 공부하고 기록합니다.

모듈을 어떻게 찾을까?

파이썬은 모듈/package를 어떻게 찾을까요?

파이썬은 아래의 순서대로 모듈을 찾는다.

1. sys.modules

2. built-in modules

3. sys.path

1. sys.modules

파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳.

sys.modules는 단순한 dictionary 입니다.

그리고 이미 import된 모듈과 package들을 저장하고 있습니다.

즉, 한번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있습니다.

그러므로 새로 import 하는 모듈은 sys.modules 에서 찾을 수 없습니다.

2. built-in modules

파이썬에서 제공하는 파이썬 공식 라이브러리들 입니다.

Built-in 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있습니다.

3. sys.path

마지막으로 보는 장소가 바로 sys.path 다.

sys.path는 기본적으로 list이며 string 요소들을 가지고 있는 list 입니다.
각 string 요소들이 나타내는 것은 파일의 경로다.

['',
 '/Users/song-eun-u/anaconda3/bin',
 '/Users/song-eun-u/anaconda3/lib/python36.zip',
 '/Users/song-eun-u/anaconda3/lib/python3.6',
 '/Users/song-eun-u/anaconda3/lib/python3.6/lib-dynload',
 '/Users/song-eun-u/anaconda3/lib/python3.6/site-packages',
 '/Users/song-eun-u/anaconda3/lib/python3.6/site-packages/aeosa',
 '/Users/song-eun-u/anaconda3/lib/python3.6/site-packages/IPython/extensions',
 '/Users/song-eun-u/.ipython']

그러므로 파이썬은 list의 각 경로를 하나 하나 확인하면서 해당 경로에 import 하고자 하는 package가 위치해 있는지 확인합니다.

sys.path 에서도 못찾으면 ModuleNotFoundError 에러를 리턴합니다.

sys.path와 sys.modules의 차이점

우선 sys.modules는 파이썬이 가장 먼저 모듈을 찾는 장소이다.
이미 import된 모듈들을 파이썬이 다시 찾지 않도록 아예 저장해놓는 것.
또한 각각의 모듈들은 dict의 형태로 저장된다.

sys.path는 파이썬이 가장 마지막으로 모듈을 찾는 장소이다.
새로 import할 모듈들이 아직 어디에 있는지 모르기 때문에 파일의 경로를 알려주는 것.
또한 각각의 모듈들은 string들의 list형태로 저장된다.

둘은 모두 sys라는 파이썬 내장모듈안에 있다.

sys는 무엇이고 어디서 올까?

sys 는 파이썬에 포함되어 있는 모듈입니다. 즉, 내장 모듈이다.
그러므로 다음 처럼 sys 모듈을 import 해서 sys.modulessys.path 를 출력할수도 있고 수정 할 수 도 있습니다.

sys가 무엇인지 출력해보면,

import sys

print(sys)

# <module 'sys' (built-in)>

모듈이고, built-in이라고 친절하게 알려준다.

sys는 built-in 모듈이고, 따라서 파이썬은 sys를 찾을 때 built-in modules에서 찾게 된다.

Absolute path와 Relative path

파이썬의 built-in 모듈pip 을 통해 설치한 외부 모듈 및 package는 일반적으로 import 하는데 큰 문제가 되지 않습니다.

Built-in 모듈은 당연히 잘 찾아지고, pip 으로 설치한 외무 모듈도 자동으로 site-packages 라는 디렉토리에 설치가 되는데, 이 site-packagessys.path에 이미 포함되어 있기때문에 찾는데 문제가 없습니다.

문제는 직접 개발한 local package 입니다. 직접 개발한 local package를 import 할때는 해당 package의 위치에 맞게 import 경로를 잘 선언해야 합니다.

Local package를 import 하는 경로에는 absolute pathrelative path 가 있습니다.

Absolute path

Absolute path는 이름 그대로 절대 경로 입니다. 왜 절대 경로인가 하니, import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하기 때문입니다.

파일들의 최상단 directory를 기준으로 하기 때문에 경로가 항상 같게 된다.
이걸 리눅스의 directory 경로 형식으로 바꾸면 다음처럼 표현 할 수 있습니다.

my_app/package2/subpackage1/module5.py

윈도우스 형식이라면 다음과 같습니다.

my_app\package2\subpackage1\module5.py

파이썬에서는 slash / 나 back slash \ 대신에 dot . 을 사용해서 경로를 표현 합니다.

my_app.package2.subpackage1.module5.py

이미 my_app 프로젝트 안에 있으므로 my_app 은 생략됩니다. 그러므로 다음처럼 경로를 표현하게 되는 것입니다.

my_app 프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 위와 같이 동일하게 되므로 absolute path 라고 하는 것입니다.

absolute path를 사용하게 되면 한가지 단점이 있는데 바로 경로가 길어질 수 있다는 점입니다.

그래서 이러한 단점을 보완하기 위해서 relative path를 사용할 수 있습니다.

relative path

Relative path 는 absolute path와 다르게 프로젝트의 최상단 디렉토리를 기준으로 경로를 잡는게 아니라 import 하는 위치를 기준으로 경로를 정의합니다.
그래서 일반적으로 relative path는 local package 안에서 다른 local package를 import 할때 사용됩니다.

Relative path는 선언해야 하는 경로의 길이를 줄여준다는 장점은 있지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있습니다.

그러므로 웬만한 경우 absolute path를 사용하는게 권장 됩니다.

absolute path와 relative path의 차이점

가장 큰 차이점은 각각의 경로가 기준으로 하는 위치이다.
absolute path의 경우 최상단 디렉토리를 기준으로 하기 때문에, 파일들의 위치가 바뀌더라도 path가 고정적이다. 반면 relative path의 경우 import하는 파일을 기준으로 하기 때문에, 파일의 위치가 바뀜에 따라 path도 바뀌게 된다.

init.py

__init__.py 파일에는 아무코드도 없지만 init 파일은 해당 디렉토리가 패키지임을 알려주는 역할을 합니다.

메인 파일에서 파일을 불러오는 법

ImportError: attempted relative import with no known parent package

보통의 파일에서는 파일을 불러올 때 절대경로와 상대경로가 선택이지만,
메인 파일에서는 무조건 절대경로로 파일들을 불러와야 한다. 메인 파일에서는 상대 경로 자체를 아예 인식하지 않는 듯하다.

Note: relative imports are based on the name of the current module. Since the name of the main module is always "main", modules intended for use as the main module of a Python application must always use absolute imports.

profile
백엔드란 무엇인GO (부족한 내용들 피드백 부탁드립니다)

관심 있을 만한 포스트

0개의 댓글