파이썬에서 필요한 모듈과 패키지를 사용하려고 하면, 파이썬은 아래와 같은 순서로 해당 모듈/패키지가 있는지 확인을 하고, 있다면 불러와서 사용할 수 있게 된다.
1) sys.modules
2) built-in modules
3) sys.path
그럼, 각각이 의미하는 것이 무엇인지를 알아보자.
sys.modules는 파이썬이 모듈/패키지를 찾기 위해 가장 먼저 확인하는 곳이다. 한 번 import된 모듈/패키지는 파이썬이 다시 찾지 않도록 저장을 해 두고 있으며, 딕셔너리 구조를 가지고 있다. 때문에 새로 import하는 모듈은 sys.modules에서 찾을 수 없다.
빌트인 모듈은 파이썬에서 공식적으로 제공하는 라이브러리들로서 파이썬 설치 시 설치되는 모듈/패키지들이다. 우리가 모듈로 작성해 두지 않지만, 파이썬에서 이미 만들어진 내장 함수들이 여기에 포함된다.
print(), len(), input(), int() 등
파이썬이 마지막으로 찾는 곳은 sys.path이다. sys.path는 모듈을 찾을 때 참조하는 경로(PC에서 파일 위치를 알려주는 디렉토리 경로처럼)로서, 그 경로들을 리스트 구조로 가지고 있다.
따라서 print(sys.path)로 출력하면 아래와 같은 디렉토리들을 리스트를 보여주게 된다.
PC에서 우리가 특정 파일을 사용하기 위해서는 디렉토리 경로를 잘 알고 있어야 되는 것처럼 파이썬에서도 1) import한 모듈/패키지가 아니거나, 2) 빌트인 모듈/패키지가 아니라면, 내가 사용하고자 하는 모듈/패키지의 위치를 정확하게 알고 있어야 한다. 만약 내가 사용하고자 하는 모듈/패키지과 1), 2), 3) 어디에서 존재하지 않는다면 ModuleNotFoundError를 리턴하게 된다.
sys.modules는 이미 import한 모듈/패키지를 찾아주는 딕셔너리 자료구조를 가지고 있고, sys.path는 해당 모듈/패키지의 디렉토리 경로를 담고 있는 리스트 자료구조를 가지고 있다는 것이 가장 큰 차이점이다.
sys모듈은 파이썬 빌트인 모듈 중 하나이다. import sys를 한 뒤 print(sys.modules)를 해 보면, 아래와 같이 빌트인 모듈이라는 것을 확인할 수 있다.
'sys': <module 'sys' (built-in)>
파이썬의 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 가 있습니다.
Absolute path는 이름 그대로 절대 경로이다. import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하기 때문입니다.
위의 디렉토리 구조를 가지고 있는 my_app 프로젝트 사례를 보자.
Absolute path를 사용할 경우, 현재 내 파일의 위치가 어디이든지 간에 module1과 module3를 import할 경우 표현식은 아래와 같이 동일하다.
위의 내용을 디렉토리 구조로 살펴보면, 아래와 같이 도식화할 수 있다. 항상 프로젝트 최상단 디렉토리 기준으로 경로가 잡힘을 알 수 있다. (my_app/package/module까지는 폴더라고 할 수 있다면, function은 파일이라고 볼 수 있겠다.)
my_app => package1 => module1
my_app => package2 => module3 => function1
반면, relative path에서는 import하는 위치를 기준으로 경로를 정의한다. 그래서 일반적으로 relative path는 local package 안에서 다른 local package를 import할 때 사용한다.
예를 들어, package2의 module3에서 package2의 class1과 package2의 하위 package인 subpackage1의 module5의 function2 함수를 import하려고 하면 다음 처럼 할 수 있다.
종합하자면, relative path는 선언해야 할 경로를 길이를 줄여준다는 장점이 있다면, import하는 위치에 따라 경로가 계속 변경해야 하는 단점이 존재한다. 따라서 웬만하면 absolute path를 사용하는 게 좋다.
[package2/module3에서 function1 import해서 사용한 사례]
패키지 내에 init.py 파일을 만들어서 초기 설정을 해 줄 수 있다. 이경우, 패키지가 import될 때 init.py는 자동으로 실행이 된다. 그렇다면, init.py를 통해 정확히 무엇을 할 수 있을까?
[줄이기 전]
import pkg.mod1
pkg.mod1.func2()
[줄이기 후]
# __init__.py
from .mod1 import func2
# main.py
from pkg import func2
func2()
모듈 중 내부적으로만 사용해야 해서 외부로 노출이 되면 안 될 때, __all__
변수를 통해 외부로 노출할 함수들을 지정해 줄 수 있다.
__all__
변수의 default 값은 모든 함수/변수/클래스이기에 지정해 두지 않으면 모든 함수들이 노출되게 된다.__all__
변수는 string 값을 요소로 가지는 list이다. 그럼으로 import되기를 원하는 요소는 string으로 list에 선언해 주면 된다.# __init__.py
from .mod1 import func2
from .mod2 import func3
__all__ = ['func2', 'func3']
# main.py
from pkg import *
func2()
func3()
func4() ## <== Error. func4 함수는 __all__ 에 정의되지 않았으므로 import 될 수 없음.
다른 사람이 만들 package를 import 하여 사용하기 위해서는 먼저 package를 설치를 해야 한다. 예를 들어, Django 라는 package를 사용하기 위해서는 먼저 설치를 해야 한다.
파이썬에서 package를 설치하는 일은 매우 간단합니다. PIP 라는 툴을 사용하면 된다. PIP는 파이썬의 package manager 이다. 파이썬을 설치하면 같이 설치가 되며 pip은 터미널에서 다음 명령어를 사용하면 된다.
pip install Django