[Python] How Import Statement Finds Modules & Packages

수야·2020년 5월 8일
0

과제

목록 보기
3/3

Import Search 순서

예를 들어, abc 라는 package가 있다고 가정해 보겠습니다. 그리고 abc package를 사용하려면 다음처럼 import 해야 합니다.

import abc

여기서 abc는 단순한 파이썬 파일(모듈일 경우) 이거나 파이썬 파일들을 담고 있는 디렉토리(package의 경우) 입니다. 그러므로 해당 파일이나 디렉토리가 어디있는지 파이썬이 찾을 수 있어야 import가 가능할것입니다.

그럼 파이썬은 module/package를 어떻게 찾을까요?
파이썬은 다음 3가지 장소를 순서대로 보면서 찾습니다.

  1. sys.modules
  2. built-in modules
  3. sys.path

sys.modules

파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳입니다.
sys.modules는 단순한 dictionary 입니다. 그리고 이미 import된 모듈과 package들을 저장하고 있습니다.
즉, 한번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있습니다.
그러므로 새로 import 하는 모듈은 sys.modules 에서 찾을 수 없습니다.

built-in modules

파이썬에서 제공하는 파이썬 공식 라이브러리들 입니다.
Built-in 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있습니다.

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 는 파이썬에 포함되어 있는 모듈입니다. 그러므로 다음 처럼 sys 모듈을 import 해서 sys.modules와 sys.path 를 출력할수도 있고 수정 할 수 도 있습니다.

import sys

print(sys.path)
print(sys.modules)

정리를 하자면, 파이썬은 import 하고자 하는 모듈과 package를 찾을때에 먼저 sys.modules를 보고, 없으면 파이썬 built-in 모듈들을 확인 하고 마지막으로 sys.path에 지정되어 있는 경로들을 확인해서 찾습니다.
sys.path 에서도 못찾으면 ModuleNotFoundError 에러를 리턴합니다.

Absolute Path & Relative Path

파이썬에서 sys.module과 built-in module은 pip와 외부 module 설치로 인해 원하는 package나 module를 찾는 데 큰 문제가 되지 않습니다.
pip로 설치한 외부 module은 자동으로 site-packages라는 디렉토리에 설치되는데, 이 site-packages는 sys.path에도 저장이 되어 찾는데 문제가 없습니다.

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

경로를 선언할때에는 'Absolute Path' 와 'Relative Path'가 있습니다.

예를들어 다음과 같은 한 프로젝트 보면...

└── my_app
    ├── main.py
    ├── package1
    │   ├── module1.py
    │   └── module2.py
    └── package2
        ├── __init__.py
        ├── module3.py
        ├── module4.py
        └── subpackage1
            └── module5.py

my_app 이라는 프로젝트안에는 package1과 package2를 갖고 있습니다.
그리고 package2에는 subpackage2라는 중첩 package를 가지고 있습니다.

여기서 package2의 subpackage1의 module5의 function2를 import하고자 한다면...

from package2.subpackage1.module5 import function2

사실상 경로를 보면 다음과 같습니다.

my_app => package2 => subpackage1 => module5.py

이걸 리눅스의 directory 경로 형식으로 바꾸면 다음처럼 표현 할 수 있습니다.

# 리눅스 형식
my_app/package2/subpackage1/module5.py

윈도우스 형식

# 윈도우스 형식
my_app\package2\subpackage1\module5.py

파이썬형식

# 파이썬 형식
package2.subpackage1.module5.py

다시 from import 키워드로 import한다면

# import
from package2.subpackage1.module5 import function2

여기서 Absolue Path는 말그대로 절대 경로로 my_app이라는 프로젝트안에서 절대 변하지 않는 경로를 말합니다.
일반적으로 local packeage를 import할때 absolute path를 사용하여 import하면 됩니다.

absolute path 사용시 단점은 경로가 길어진다는 점입니다.

이에 비해 Relative Path는 최상단 디렉토리 기준으로 경로를 잡는것이 아니라 import하는 위치를 기준으로 경로를 정의합니다. 그래서 일반적으로 relative path는 local package 안에서 다른 local package를 import 할 때 사용합니다.

# package2/module3.py

from . import class1
from .subpackage1.module5 import function2

상위 디렉토리를 선언해줄수 있습니다.

# subpackage1/module5.py
from ..module4 import class4

절대경로 상대경로 실습

위와 같은 구조로 파일들을 생성하고 저장하였습니다.
각 파일들의 내용을 보면....

이제 main.py를 통해 절대경로로 설정하고 코드를 실행하였습니다.

잘 실행이 된 것을 확인할 수 있습니다.
그러나 여기서 상대경로로 설정하고 실행을 하게 되면....

'ImportError: attempted relative import with no known parent package`

위와 같은 에러가 발생합니다.
되도록 코드를 실행할 때는 절대경로를 사용하길 바랍니다!

Assignment

1. sys.modules 와 sys.path의 차이점을 서술해 주세요.

1-1. sys.modules

sys.module은 파이썬이 module이나 package를 찾을 때 가장 먼저 확인하는 곳으로, dicitonary 형태로 구성되어 있다.

1-2. sys.path

sys.path는 파이썬이 마지막으로 보는 장소로, string 요소들을 가지고 있는 list 형식으로 구성되어 있다.

2. sys 도 import 해야하는 모듈입니다. 파이썬은 sys 모듈의 위치를 어떻게 찾을 수 있을까요?

sys는 파이썬에 기본적으로 포함되어 있는 module로, sys.module 디렉토리 또는 sys.path 경로를 확인하여 module의 위치를 확인 할 수 있다.

python은 sys.modules -> built-in modules -> sys.path 순으로 모듈을 찾는다. sys는 built-in module이다. 때문에 import sys를 하면 파이썬은 built-in 모듈에서 sys를 찾아 실행한다.

3. Absolute path와 relative path의 차이점을 서술해 주세요.

Absolute Path는 절대적인 경로로, module이나 packageimport 할때 최상위 경로부터 선언하여야한다. 일반적으로 local package를 import할때 사용한다.

Relative Path는 상대적인 경로로, module이나 packageimport 할때, 현재 자신의 위치를 기준으로 상대적인 경로를 선언한다. 일반적으로 local package안에 다른 local package를 import할때 사용한다.



참고링크

https://velog.io/@inyong_pang/Python-How-Import-Statement-Finds-Modules-Packages

profile
운동을 좋아하는 QA 및 개발자

0개의 댓글