파이썬에서 module은 변수나 함수 그리고 클래스 등을 모아놓은 파일이다.
다른 파일에서 재사용이 가능하게 하고 전체 코드가 하나의 파일에 넣기에는 너무 커졌을때 여러 파일로 나누어서 정리한 후 관리하기 위해서 사용합니다.
## my_module.py
def getSum(a,b):
return a+b
def getDiff(a,b):
if a > b:
return a-b
else:
return b-a
2-1. Module 불러오고 사용하기 - import 키워드만 사용해서 불러오기
import <module_name>
## main.py
import my_module
x = 2
y = 3
print(my_module.getSum(x,y)) # => 5
print(my_module.getDiff(x,y)) # => 1
2-2. from import 키워드 사용하기
from <module_name> import <func/var/class>, <func2/var2/class2>, ...
## main.py
from my_module import getSum, getDiff
print(getSum(2,3)) # => 5
print(getDiff(5,2)) # => 3
from <module_name> import * 을 사용하면 해당 모듈의 모든 요소가 바로 import된다.
## main.py
from my_module import *
print(getSum(2,3)) # => 5
print(getDiff(5,2)) # => 3
2-3. import as - 모듈이나 모듈안에서 import할 요소들에게 새로운 이름을 부여해서 사용할 수 있다.
## main.py
import my_module as mm
print(mm.getSum(2,3)) # => 5
print(mm.getDiff(5,2)) # => 3
## main.py
from my_module import getSum as gs
from my_module import getDiff as gd
print(mm.gs(2,3)) # => 5
print(mm.gd(5,2)) # => 3
모듈과 마찬가지로 다른 파일에서 불러와서 사용한다는 개념인데, 차이점은 모듈보다 더 크고 복잡한 코드라는 것이다. 모듈은 단순한 파이썬 파일이지만 패키지는 파이썬 파일들로 이루어져 있는 디렉토리이다.
위에 이미지처럼 구성 되었다고 가정하면 아래와 같이 활용할 수 있다.
import pkg.mod1
from pkg.mod2 import func2
pkg.mod1.func2()
func2()
가끔은 package가 import 될때 초기 설정을 해줘야 할때가 있다.
파이썬은 __init__.py 파일을 통해 package 초기 설정을 가능하게 해준다.
Package 안에 __init__.py 파일이 있으면 package가 import 될때 __init__.py 파일의 코드들이 자동으로 실행된다.
__intit__.py 를 통하여 할 수 있는 것들
__init__.py 파일에 먼저 한번 import 해주면
__init__.py 파일을 통해 함수의 경로를 줄여줄 수 있다.
#__init__.py
from .mod1 import func2
#main.py
from pkg import func2 #모듈을 언급하지 않아도 됨
func2()
모듈의 모든 함수가 다 외부로 노출될 수 있는건 아닐수 있다. 내부적으로만 사용되어야 하는 함수도 있을수 있는데, 이러한 함수가 package 외부에서 import되어 사용되는 것을 막기 위해서는 __all__ 변수를 지정해 줄 수 있습니다.
package를 통해 import 될 수 있는 요소들은 모두 __all__ 변수를 통해 정의 된다.
그리고 __all__ 변수의 default 값은 모든 함수/변수/클래스 이다.
그러므로 __all__ 변수를 따로 정의해줌으로 import 될 수 있는 요소들을 제한할 수 있는 것이다.
__all__ 변수는 string 값의 요소를 가지고 있는 list 이다 (list of strings).
그러므로 import 되길 원하는 요소들을 string으로 list에 선언해주면 된다.
# __init__.py
from .mod1 import func2
from .mod2 import func3
__all__ = ['func2', 'func3']
# main.py
from pkg import func2
from pkg import func3
func2()
func3()
func4() ## <=Error. func4 함수는 __all__에 정의되지 않았음.
위에서 모듈과 패키지에 대해서 간단히 알아보았다. 그렇다면 모듈과 패키지를 불러올 때 사용되는 'import'는 어떤 방식으로 모듈과 패키지를 찾아내는지에 대해 알아보자.
예를 들어, pkg라는 패키지가 있다고 가정하고 해당 패키지를 사용하려면 다음과 같이 import 해야한다.
import pkg
코드만 보았을 때 'pkg'는 모듈(파이썬 파일)이거나 모듈을 담고있는 디렉토리 이거나 둘 중 하나이다. 그러므로 import를 하기 위해서는 해당 파일이나 디렉토리의 경로를 파이썬이 찾을 수 있어야한다.
파이썬이 모듈이나 패키지를 찾을 때 검색하는 순서는 아래와 같다.
1. sys.modules
2. built-in modules
3. sys.path
파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳이다.
sys.modules는 dictionary 이며 이미 import된 모듈과 package들을 저장하고 있다.
즉, 한번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있다.
새로 import 하는 모듈은 sys.modules 에서 찾을 수 없습니다.
파이썬에서 제공하는 파이썬 공식 라이브러리들 이다.
Built-in 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있다.
sys.path는 기본적으로 list이며 string 요소들을 가지고 있는 list 입니다. 각 string 요소들은 다음 처럼 경로를 나타낸다.
['/run_dir', '/usr/local/lib/python38.zip',
'/usr/local/lib/python3.8',
'/usr/local/lib/python3.8/lib-dynload',
'/home/runner/.local/share/virtualenvs/python3/lib/python3.8/site-packages']
이러한 리스트에 있는 각 경로를 하나씩 확인하면서 해당경로에 import 하고자 하는 패키지가 위치해 있는지 확인한다.
sys.modules는 이미 import된 모듈이나 패키지를 보여주는 것이고 sys.path는 모듈이나 패키지를 찾는 과정에서 검색하는 경로들을 보여준다.
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 가 있다.
import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하다.
경로들의 시작점이 전부 프로젝트의 가장 최상위 디렉토리에서 시작한다.
프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 정해져있기 때문에 프로젝트의 최상위 디렉토리를 기준으로 경로를 기재하는 것을 absolute path 라고 한다.
일반적으로 local package를 import 할때는 absolute path를 사용하면 된다. 다만, absolute path를 사용하게 되면 경로가 길어질 수 있다는 단점이 있다. 이러한 단점을 보완하기 위해서 relative path를 사용할 수 있다.
Relative path 는 absolute path와 다르게 프로젝트의 최상단 디렉토리를 기준으로 경로를 잡는게 아니라 import 하는 위치를 기준으로 경로를 정의한다. 그래서 일반적으로 relative path는 local package 안에서 다른 local package를 import 할때 사용된다.
Relative path는 선언해야 하는 경로의 길이를 줄여준다는 장점은 있지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있다. 그러므로 웬만한 경우 absolute path를 사용하는게 권장 된다.
공식문서를 참조하면 상대 경로를 사용 하면 안되는 경우를 알려주는데
본문
Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
번역
상대 경로는 현재 모듈의 이름을 기반으로 한다. 메인 모듈의 이름은 항상 "__main__"이기 때문에 파이썬 애플리케이션의 메인 모듈로 사용하기 위한 모듈들은 항상 절대 경로를 사용해야 한다.
내용으로 보아, 파이썬이 어떤 프로젝트에서 경로들을 설정 할 때, 메인 파일을 기준으로 하기 때문에 메인모듈에는 절대경로를 명시해 줘야 한다는것 같다. (물론 뇌피셜)