예를 들어, abc 라는 package
가 있다고 가정해 보겠습니다. 그리고 abc package를 사용하려면 다음처럼 import
해야 합니다.
import abc
여기서 abc는 단순한 파이썬 파일(모듈일 경우) 이거나 파이썬 파일들을 담고 있는 디렉토리(package의 경우) 입니다. 그러므로 해당 파일이나 디렉토리가 어디있는지 파이썬이 찾을 수 있어야 import
가 가능할것입니다.
그럼 파이썬은 module/package
를 어떻게 찾을까요?
파이썬은 다음 3가지 장소를 순서대로 보면서 찾습니다.
파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳입니다.
sys.modules는 단순한 dictionary 입니다. 그리고 이미 import된 모듈과 package들을 저장하고 있습니다.
즉, 한번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있습니다.
그러므로 새로 import 하는 모듈은 sys.modules 에서 찾을 수 없습니다.
파이썬에서 제공하는 파이썬 공식 라이브러리들 입니다.
Built-in 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있습니다.
마지막으로 보는 장소가 바로 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 에러를 리턴합니다.
파이썬에서 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`
위와 같은 에러가 발생합니다.
되도록 코드를 실행할 때는 절대경로를 사용하길 바랍니다!
sys.module은 파이썬이 module이나 package를 찾을 때 가장 먼저 확인하는 곳으로, dicitonary 형태로 구성되어 있다.
sys.path는 파이썬이 마지막으로 보는 장소로, string 요소들을 가지고 있는 list 형식으로 구성되어 있다.
sys는 파이썬에 기본적으로 포함되어 있는 module로, sys.module 디렉토리 또는 sys.path 경로를 확인하여 module의 위치를 확인 할 수 있다.
python은 sys.modules -> built-in modules -> sys.path 순으로 모듈을 찾는다. sys는 built-in module이다. 때문에 import sys를 하면 파이썬은 built-in 모듈에서 sys를 찾아 실행한다.
Absolute Path는 절대적인 경로로, module
이나 package
를 import
할때 최상위 경로부터 선언하여야한다. 일반적으로 local package를 import
할때 사용한다.
Relative Path는 상대적인 경로로, module
이나 package
를 import
할때, 현재 자신의 위치를 기준으로 상대적인 경로를 선언한다. 일반적으로 local package안에 다른 local package를 import
할때 사용한다.
https://velog.io/@inyong_pang/Python-How-Import-Statement-Finds-Modules-Packages