~파이썬과 모듈에 대한 개념은 앞선 포스팅 참고~
이번에는 파이썬이 module과 package를 찾기 위해 어떻게 검색을 하는지 알아보자.
abc
라는 package가 있다고 가정하자. 그리고 abc package를 사용하려면 다음처럼 import 해야 한다.
import abc
여기서 abc
는 단순한 파이썬 파일(모듈일 경우) 이거나 파이썬 파일들을 담고 있는 디렉토리(package의 경우)다. 그러므로 해당 파일이나 디렉토리가 어디있는지 파이썬이 찾을 수 있어야 import가 가능할것입니다.
파이썬은 다음 3가지 장소를 순서대로 보면서 모듈과 package를 찾는다.
sys.modules
built-in modules
sys.path
파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳이다. sys.modules
는 단순한 dictionary 다. 그리고 이미 import된 모듈과 package들을 저장하고 있다.
즉, 한번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있다.
그러므로 새로 import 하는 모듈은 sys.modules 에서 찾을 수 없으니 주의하자.
파이썬에서 제공하는 파이썬 공식 라이브러리들이다. Built-in 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있다.
마지막으로 보는 장소가 바로 sys.path
다. sys.path
는 기본적으로 list이며, string 요소들을 가지고 있는 list 다.
각 string 요소들은 다음 처럼 경로를 나타낸다.
그러므로 파이썬은 list의 각 경로를 하나 하나 확인하면서 해당 경로에 import 하고자 하는 package가 위치해 있는지 확인한다.
참고로 sys 는 파이썬에 포함되어 있는 모듈이다. 그러므로 다음 처럼 sys 모듈을 import 해서 sys.modules
와 sys.path
를 출력할수도 있고 수정 할 수 도 있습니다.
ModuleNotFoundError
에러를 리턴한다.
파이썬의 built-in 모듈과 pip
을 통해 설치한 외부 모듈 및 package는 일반적으로 import 하는데 큰 문제가 되지 않는다.
Built-in 모듈은 당연히 잘 찾아지고, pip
으로 설치한 외무 모듈도 자동으로 site-packages
라는 디렉토리에 설치가 되는데, 이 site-packages
는 sys.path
에 이미 포함되어 있기때문에 찾는데 문제가 없기 때문이다.
문제는 직접 개발한 local package 이다. 직접 개발한 local package를 import 할때는 해당 package의 위치에 맞게 import 경로를 잘 선언해야 한다.
Local package를 import 하는 경로에는 absolute path 와 relative path 가 있다.
import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하기 때문에 절대 경로라고 한다.
다음과 같은 프로젝트를 예를 들어 보자.
└── my_app
├── main.py
├── package1
│ ├── module1.py
│ └── module2.py
└── package2
├── __init__.py
├── module3.py
├── module4.py
└── subpackage1
└── module5.py
my_app
이라는 프로젝트 이며, package1
과 package2
라는 2개의 package를 가지고 있다. 그리고 package2
는 subpackage2
라는 중첩 package를 가지고 있다.
Absolute path를 사용해 package1
과 package2
를 import 하면 다음과 같습니다.
from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2
경로들의 시작점이 전부 my_app
프로젝트의 가장 최상위 디렉토리에서 시작하는것을 볼 수 있다. 예를 들어, subpackage1
의 module5
모듈의 function2
함수를 import 하기 위해서는 다음 경로를 거치게 된다.
my_app => package2 => subpackage1 => module5.py
리눅스의 directory 경로 형식(
slash /
)my_app/package2/subpackage1/module5.py
윈도우스의 directory 경로 형식(
back slash \
)my_app\package2\subpackage1\module5.py
파이썬의 directory 경로 형식(
dot .
)my_app.package2.subpackage1.module5.py
이미 my_app
프로젝트 안에 있으므로 my_app
은 생략된다. 그러므로 다음처럼 경로를 표현하게 된다.
package2.subpackage1.module5.py
이걸 from import 키워드를 사용해 import 하게 되면 다음 처럼 된다.
from package2.subpackage1.module5 import function2
my_app
프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 위와 같이 동일하게 되므로 absolute path 라고 한다.
참고로 current directory 라고 하는 현재의 프로젝트 디렉토리는 default로 sys.path 에 포함된다. 그러므로 absolute path는 current directory 로 부터 경로를 시작하게 되는것이다.
일반적으로 local package를 import 할때는 absolute path를 사용하면 된다. 다만, absolute path를 사용하게 되면 한가지 단점이 있는데 바로 경로가 길어질 수 있다는 점이다.
이러한 absolute path의 단점을 보완하기 위해서 relative path를 사용할 수 있다.
Relative path 는 absolute path와 다르게 프로젝트의 최상단 디렉토리를 기준으로 경로를 잡는게 아니라 import 하는 위치를 기준으로 경로를 정의한다. 그래서 일반적으로 relative path는 local package 안에서 다른 local package를 import 할때 사용된다.
예를 들어, package2
의 module3
에서 package2
의 class1
과 package2
의 하위 package인 subpackage1
의 module5
의 function2
함수를 import 하려고 하면 다음 처럼 할 수 있다.
# package2/module3.py
from . import class1
from .subpackage1.module5 import function2
여기서 dot .
은 import 가 선언되는 파일의 현재 위치를 의미한다. 현재위치는 package2/module3.py
이므로 현재 위치에서부터 원하는 모듈의 경로만 선언해주면 되는 것이다.
또한 dot 2개를 사용할 수도 있다. dot 2개 ..
는 현재위치에서 상위 디렉토리로 가는 경로다.
# subpackage1/module5.py
from ..module4 import class4
Relative path는 선언해야 하는 경로의 길이를 줄여준다는 장점은 있지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있습니다.
그러므로 웬만한 경우 absolute path를 사용하는게 권장 된다.