sys.modules
→ 이미 import된 모듈/패키지를 저장하고 있음
built-in modules
→ 파이썬에서 제공하는 공식 라이브러리
sys.path
→ 경로들의 리스트로, 각 경로를 확인하면서 import할 모듈/패키지를 검색한다. 기본적으로 프로젝트 경로가 포함되어 있다.
import sys
print(sys.path)
# ['/Users/songjinsu/vscode', '/Library/Frameworks/Python.framework/Versions/3.9/lib/python39.zip', '/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9', '/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages']
vscode 폴더 디렉토리가 포함되어 있어 vscode 폴더 내부에 있는 모듈/패키지를 import할 수 있다.
만약 직접 만든 모듈/패키지가 sys.path 경로 상에 없다면 sys.path에 원하는 경로를 추가하거나, sys.modules에 직접 모듈/패키지를 리스트에 추가하는 방법도 있다.
import sys
print(sys.modules)
# {'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap' (frozen)>, '_imp': <module '_imp' (built-in)>, '_thread': <module '_thread' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_weakref': <module '_weakref' (built-in)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>, '_frozen_importlib_external': ........
sys.modules는 이미 import된 모듈/패키지들을 딕셔너리형으로 이름과 모듈의 빌트인 여부(아닐 경우 모듈/패키지의 경로)를 저장하고 있다.
sys.path는 import하고자 하는 모듈/패키지가 modules에 없고, 빌트인도 아닐 경우 검색하는 경로들의 리스트이다.
한편 sys 또한 모듈인데 어떻게 import를 해올까?
위 sys.modules에 나와있는 것처럼 sys도 빌트인 모듈이므로, sys를 import한 적이 없었다면 빌트인 모듈/패키지를 검색하는 2번째 단계에서 찾을 수 있을 것이다.
import를 할 때, 프로젝트의 최상단 디렉토리를 기준으로 한다면 절대경로, import하는 위치를 기준으로 한다면 상대경로이다.
예를 들어, vscode라는 이름의 프로젝트 내에 있는 모듈(module1.py)에서 같은 위치에 있는 모듈(module2.py)를 import 하고자 할 때,
절대경로 : vscode.module2
상대경로 : .module2 (' . ' 하나는 import하는 위치와 같은 위치이다.)
vscode 프로젝트 내 어느 폴더(folder1)에 있는 모듈에서 상위 디렉토리, 즉 vscode 폴더 내의 모듈(module3.py)를 import 하고자 할 때,
절대경로 : vscode.module3
상대경로 : ..module3 (' . ' 두 개는 상위 디렉토리를 뜻한다.)
vscode 폴더 하위에 main.py 파일과 calculator 폴더를 추가하고, calculator 폴더에 아래와 같은 모듈들을 추가했다.
그리고 main.py에 아래와 같이 경로 방식에 따른 코드를 작성했다.
#absoulte path
#from calculator.add_and_multiply import add_and_multiply
# relative path
#from .calculator.add_and_multiply import add_and_multiply
if __name__ == '__main__':
print(add_and_multiply(1,2))
위의 함수를 절대경로로 import시 문제 없이 import가 가능하나, 상대경로를 사용할 경우 에러가 발생한다.
이 에러는 실행되는 모듈의 namespace가 '__main__' 으로 고정되는 것 때문에 발생한다. 상대경로는 import를 실행하는 모듈의 위치를 기준으로 경로를 탐색하는데, 기준이 되는 것이 '모듈의 이름(namespace)'이다. 따라서 상대경로를 이용하려면 파이썬 인터프리터가 실행되는 모듈이 아닌 모듈(__init__.py 같은 패키지 내부 모듈) 에서나 사용할 수 있다.
# add_and_multiply.py
#상대경로
#from .multiplication import multiply
#절대경로
from calculator.multiplication import multiply
def add_and_multiply(a,b):
return multiply(a,b) + (a+b)
main.py를 실행할 때에는 add_and_multiply.py에 상대경로를 넣든 절대경로를 넣든 상관없이 5가 잘 출력된다.
그러나 add_and_multiply.py를 직접 실행할 경우, 상대경로는 윗 문단 설명과 같이 ImportError가 발생하고, 절대경로는 아래와 같은 에러가 발생한다.
이는 절대경로가 '현재 디렉토리'에서 시작하기 때문인데,
add_and_multiply.py 내에서 sys.path를 호출하면 아래와 같은 경로들이 출력된다.
위 그림과 같이 현재 디렉토리는 이미 'calculator'이기 때문에 절대경로를 올바르게 고치면 아래와 같다.
from multiplication import multiply
__init__.py 는 패키지 내부에서 초기화 역할을 하는 모듈로, 활용할 수 있는 방법들이 몇 가지 있다.
패키지의 특정 모듈의 함수를 곧바로 호출할 수 있게 해주어 함수의 경로를 줄여줄 수 있다.
import할 수 있는 변수/함수/클래스를 '__all__' 이라는 리스트에 포함된 이름을 가진 변수/함수/클래스로 제한할 수 있다.
패키지가 import될 때 실행되어야 하는 코드들을 설정해놓을 수 있다.
정말 설명 잘 해주시네요. 검색해봐도 이렇게 정확한 글은 찾기 힘들었는데 감사합니다