파이썬에서는 모듈과 패키지를 다음과 같은 순서로 찾는다.
1. sys.modules
2. built-in modules
3. sys.path
built-in modules
는 파이썬에서 제공하는 파이썬 공식 라이브러리들이다. 이미 파이썬에 포함되어 나오므로 파이썬이 찾기에 쉽다. sys
는 파이썬에 포함되어 있는 모듈이다. 그러므로 다음과 같이 sys
모듈을 import해서 sys.modules
와 sys.path
를 출력할 수도 있고 수정할 수도 있다.
import sys
print(sys.path)
print(sys.modules)
sys.modules
는 파이썬이 모듈이나 패키지를 찾기 위해서 가장 먼저 확인하는 곳이다. 그리고 sys.modules
는 단순한 딕셔너리구조이다. 이미 import 되어있는거나 한번 import한 모듈과 패키지를 저장하므로 파이썬이 또 다시 찾지 않아도 된다. 하지만 새로 import 하는 모듈은 sys.modules
에서 찾을 수 없다.
정리하면 다음과 같다.
sys.path
는 파이썬이 가장 나중에 보는 장소이다. sys.path
는 string 요소를 갖고있는 list 이다. (list of strings)
각 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']
파이썬은 이 리스트의 각 경로를 처음부터 끝까지 확인하면서 해당 경로에 import 하려는 패키지나 모듈이 있는지 확인한다.
sys.path
에서도 찾지 못한다면 ModuleNotFoundError
에러를 리턴한다.
정리하면 다음과 같다.
sys.modules
=> built-in modules
순서로 경로를 찾고 못찾으면 sys.path
에서 찾는다.sys.path
에서도 못찾으면 ModuleNotFoundError
에러를 리턴한다.가장 큰 차이점은 sys.modules
는 dictionary형태이고, sys.path
는 list형태이다. 그리고 sys.modules
는 파이썬이 가장 먼저 경로를 찾는 곳이고, sys.path
는 가장 나중에 보는 곳이다.
파이썬은 스크립트 실행시 PYTHONPATH
, 환경설정, 변수, 위의 모듈들을 순차적으로 실행한다. 이러한 써드파티는 설치시 자동으로 절대경로가 설정이되어 찾기 쉽다.
Absolute path는 이름 그대로 절대경로이다. import 하는 파일이나 경로에 상과없이 항상 경로가 동일하기 때문이다.
위와 같은 my_app
프로젝트로 예를 들면, package1
과 package2
를 절대경로로 import 하면 다음과 같다.
from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2
경로의 시작점이 전부 my_app
프로젝트의 가장 최상위 디렉토리에서 시작한다.
파이썬에서는
my_app.package2.subpackage1.module5.py
와 같이 표시될 수 있는데 이미 my_app
안에 있기 때문에 my_app
은 생략되고 다음과 같이 표현한다.
package2.subpackage1.module5.py
#from import 로 표현
from package2.subpackage1.module5 import function2
my_app
프로젝트 내에서 어느 파일이나 어느 위치에서 import 하더라도 경로가 항상 같기때문에 absolute path라고 한다.
하지만 절대경로는 경로가 복잡해질수록 경로가 길어질 수 있다는 단점이 있다. 이 단점을 보완할 수 있는것이 relative path이다. Relative path는 프로젝트의 최상단 디렉토리가 기준이 아니라 import 하는 위치를 기준으로 경로를 정의하기때문에 일반적으로 local package 안에서 다른 locap package를 import 할 때 사용된다.
예를 들어, package2의 module3에서 package2의 class1과 package2의 하위 package인 subpackage1의 module5의 function2 함수를 import하려고 하면 다음 처럼 할 수 있다.
# package2/module3.py
from . import class1
from .subpackage1.module5 import function2
여기서 .
은 import가 선언되는 파일의 현재 위치를 의미한다. ..
은 상위 디렉토리로 가는 경로로 다음과 같이 사용할 수 있다.
# subpackage1/module5.py
from ..module4 import class4
Relative path는 Absolute path의 경로를 보다 짧게 표현할 수 있지만, 헷갈리기가 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있다. 그래서 보통의 경우 Absolute path를 사용하는 것이 권장된다.
위와 같은 상태일때 main.py
를 실행하면 다음과 같은 오류가 발생한다.
이 오류가 발생하는 이유는 main.py
가 최상위 경로에 있기 때문이다. 이런 경우에는 상대경로는 사용할 수 없고 절대경로만 사용해야 한다.
main.py
에서 절대경로로 설정해주면 제대로 import 되는 것을 다음과 같이 확인할 수 있다.
add_and_multiply.py
에서는 상대경로나 절대경로나 둘 다 muliply
함수를 import 했을 때 main.py
에서 정상적으로 동작하였다. 위에서 말한 것처럼 main 모듈에서는 상대경로로 접근할 수 없지만 그렇지 않은 경우에는 상대경로로 접근해도 문제 없다.
__init__.py
파일의 역할__init__.py
파일에는 아무코드도 없지만 init 파일은 해당 디렉토리가 패키지임을 알려주는 역할을 한다. __init__.py
는 어떤 패키지나 모듈을 불러올 때 우선 실행되는 파일이다.
가끔은 package가 import 될때 초기 설정을 해줘야 할때가 있다. 파이썬은 __init__.py
파일을 통해 package 초기 설정을 가능하게 해준다.
__init__.py
파일이 있으면 package가 import 될때 __init__.py
파일의 코드들이 자동으로 실행된다.
일반적으로 다음과 같은 초기 설정을 할 수 있다.
현재 pkg에서 mod1의 func2 라는 함수를 import 하여 사용하기 위해서는 다음과 같이 해야한다.
import pkg.mod1
pkg.mod1.func2()
func2 함수를 호출 할때마다 매번 모든 경로를 다 타입해줘야 하기때문에 번거롭지만 __init__.py
파일을 통해 함수의 경로를 줄여줄 수 있다.
__init__.py
파일에 먼저 다음과 같이 import 해주면 된다.
# __init__.py
from .mod1 import func2
이렇게 import한 후 다음과 같이 함수를 짧게 호출할 수 있다.
# main.py
from pkg import func2
func2()
__init__.py
파일을 사용해서 import 할 수 있는 변수/함수/클래스를 제한할 수 있다.
내부적으로만 사용되어야 하는 함수가 package 외부에서 import되어 사용되는 것을 막기 위해서는 __all__
변수를 지정해 줄 수 있다.
__all__
변수를 통해 정의 된다.__all__
변수의 default 값은 모든 함수/변수/클래스 이다. __all__
변수를 따로 정의해줌으로 import 될 수 있는 요소들을 제한할 수 있다.__all__
변수는 string 값의 요소를 가지고 있는 list 이다. (list of strings). # __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 될 수 없음.