[Python] 모듈/패키지 Import

송진수·2021년 7월 8일
0

Import Search 순서

  1. sys.modules
    → 이미 import된 모듈/패키지를 저장하고 있음

  2. built-in modules
    → 파이썬에서 제공하는 공식 라이브러리

  3. sys.path
    → 경로들의 리스트로, 각 경로를 확인하면서 import할 모듈/패키지를 검색한다. 기본적으로 프로젝트 경로가 포함되어 있다.


예를 들어 vscode의 프로젝트 내에서 sys.path를 출력할 경우
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에 직접 모듈/패키지를 리스트에 추가하는 방법도 있다.

sys : sys.modules 와 sys.path의 차이점

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 (' . ' 두 개는 상위 디렉토리를 뜻한다.)


절대경로는 경로명이 길어질 수 있다는 단점이 있지만, import를 하는 파일의 위치가 변경되면 상대경로를 수정해야 하므로 절대경로를 사용하는 것이 웬만하면 바람직하다.

패키지를 직접 만들어 import 해보기

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))

__main__ 에서는 절대경로만 사용할 수 있다

위의 함수를 절대경로로 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 의 역할

__init__.py 는 패키지 내부에서 초기화 역할을 하는 모듈로, 활용할 수 있는 방법들이 몇 가지 있다.

  1. 패키지의 특정 모듈의 함수를 곧바로 호출할 수 있게 해주어 함수의 경로를 줄여줄 수 있다.

  2. import할 수 있는 변수/함수/클래스를 '__all__' 이라는 리스트에 포함된 이름을 가진 변수/함수/클래스로 제한할 수 있다.

  3. 패키지가 import될 때 실행되어야 하는 코드들을 설정해놓을 수 있다.

profile
보초

1개의 댓글

comment-user-thumbnail
2022년 9월 17일

정말 설명 잘 해주시네요. 검색해봐도 이렇게 정확한 글은 찾기 힘들었는데 감사합니다

답글 달기