TIL | python modules & packages

8718 단어 pythonTILTIL

module & package

파이썬의 module은 variable, def, class 들을 모아둔 하나의 .py 파일이다. package는 그 모듈 파일들의 컨테이너로 여러 모듈들이 담겨져 있는 디렉토리로 볼 수 있다. 하나의 패키지에는 단지 모듈들만 포함 되어 있는 것이 아닌 서브 패키지가 하위로 존재할 수 있다.

파이썬에서 모듈과 패키지를 찾는 과정

파이썬에서 모듈을 사용하기 위해 import 라는 키워드를 통해 모듈을 불러 올 수 있는데 파이썬은 sys.modules, built-in.modules, sys.path 를 순서대로 검색하여 해당 모듈을 찾는다. 만약 찾지 못하면 ModuleNotFoundError 에러를 리턴한다.

sys.modules

파이썬의 모듈이나 패키지를 찾기 위해 제일 먼저 확인하는 곳이다. sys.modules는 이미 import된 모듈과 패키지들을 저장해 놓은 딕셔너리이다. 한 번 import된 모듈과 패키지들은 파이썬이 또 다시 찾지 않도록 하는 기능을 가졌다.

built-in modules

파이썬에서 제공하는 파이썬 공식 라이브러리들이다. built-in 모듈들은 이미 파이썬에 포함되어 나온다. 그러므로 파이썬이 쉽게 찾고 읽을 수 있다.

sys.path

list 자료 타입이며 모듈과 패키지들의 경로 정보를 담은 string 타입의 요소들이 담겨 있다. 파이썬은 sys.path의 요소들을 하나 하나 검색해 가며 해당 경로에 import 하고자 하는 패키지가 위치해 있는 지 확인한다.

sys 모듈

sys는 파이썬 기본 내장 라이브러리에 포함 되어 있는 모듈이다. 따라서 sys 모듈을 임포트한 후, sys.modules와 sys.path를 출력하면 값을 확인할 수 있다.

# sys module 임포트
import sys

# sys.modules 출력
print(sys.modules)
{...} # dictionary

# sys.path 출력
print(sys.path)
[...] # list 

sys.modulessys.path는 각각 딕셔너리, 리스트 타입으로 각각 다른 자료 구조로 되어 있으며 sys.modules은 import된 모듈과 패키지를 다시 찾지 않아도 되는 기능이 있다. 그러나 sys.path는 list 속 요소인 검색 경로들을 하나 씩 확인하는 방식으로 파이썬이 모듈을 찾아야 하는 차이가 있다.


Absolute path (절대 경로) & Relative path (상대 경로)

일반적으로 import를 하여 해당 모듈이나 패키지를 쉽게 찾을 수 있지만 직접 개발한 local package를 import할 때는 해당 패키지의 위치에 맞게 경로를 선언해야 정확히 임포트 할 수 있다.

Absoulute path (절대 경로)

Absolute path는 이름 그대로 절대 경로이다. 왜 절대 경로인가. import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하기 때문이다. 다음의 my_app이란 프로젝트 내에서 package1과 package2를 임포트 하는 경우에는 최상위 디렉토리인 my_app에서 경로를 표시한다.

  • my_app
    - main.py
    • package1
      • modul1.py
      • modul2.py
    • package2
      • init.py
      • module3.py
      • subpackage1
        - module5.py
from package1 import module1

from package1.module2 import function2

from package2 import class1

from package2.subpackage1.module5 import function2

Relative path (상대 경로)

# 현재 위치
# package1/module2.py

from . import class1
from .subpackage1.module5 import function2

Relative path란 import를 하는 위치를 기준으로 경로를 정의하는 방식이다. .은 현재 위치를 뜻하는 것으로 절대 경로와 같이 현재 위치의 최상단부터 작성하지 않아도 .으로 현재 위치를 표기할 수 있다. ..도 사용할 수 있는데 이는 현재 위치의 상위 디렉토리로 가는 경로를 뜻한다. 절대 경로와 달리 경로 값이 짧아져서 유용하지만 방대한 양의 데이터에서는 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있다. 그러므로 보통 절대 경로를 사용하는 것을 권장한다.

__init__.py

__init__.py 파일 패키지에 있는 파일로 아무 내용을 담지 않아도 패키지 디렉토리에 존재함으로서 이 폴더가 패키지임을 인식(파이썬 3.3 이상부터는 __init__.py이 없어도 패키지로 인식)시킨다. __init__.py는 패키지의 초기 설정을 할 수 있는 파일이며, 패키지가 import 될 때, 자동으로 실행된다. 패키지 내부에서 특정 함수나 모듈, 변수 등을 제한하여 import 하도록 설정하고 싶은 경우 __all__ 변수에 정의함으로써 가능하다.

만약 calculator_package라는 패키지를 만든다고 하자. 먼저 디렉토리를 생성하고 __init__.py 파일을 저장한다. 그 다음 원하는 모듈이름.py 모듈 파일을 패키지 디렉토리에 저장한다.

calculator_package 구조

calculator_package에는 __init__.py 파일, multiplication.py, add_and_multiply.py 두 개의 모듈이 포함 되어 있으며 calculator_package 그 상단 디렉토리에는 main.py 라는 실행 파이썬 파일이 존재한다.

  • calculator_package
    __init__.py
    multiplication.py
    add_and_multiply.py
  • main.py

multiplication 모듈

def multiply(a,b):
    return(a*b)

add_and_multiply 모듈

# 절대 경로로 multiply 모듈 import
from calculator_package.multiplication import multiply

# 상대 경로로 multiply 모듈 import
# from .multiplication import multiply

def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)

main.py 에서의 실행

main.py에서 calculator_packageadd_and_multiply를 임포트 한다고 가정하자. calculator_package와 같은 디렉토리에 속해 있는 main.py는 임포트 방식에서 절대 경로와 상대 경로를 사용한 경우, 상대 경로를 사용한 쪽에서 에러가 난다.

# main.py

# 절대 경로로 임포트 하는 경우
from calculator_package.add_and_multiply import add_and_multiply

print(add_and_multiply(1,2))
# 5

# 상대 경로로 임포트 하는 경우
from .calculator_package.add_and_multiply import add_and_multiply

print(add_and_multiply(1,2))
# ImportError: attempted relative import with no known parent package

그 이유는 .을 사용한 동시에 경로는 현재의 위치(main.py)를 의미하게 된다. 결국 main.py 파일에서의 calculator_package를 찾게 되고 이는 main.py에서 존재하지 않는 모듈 혹은 파일이므로 임포트 오류가 난다. 어떤 경로 위치에서 어떻게 import를 하느냐는 매우 중요하다. 상대 경로는 절대 경로에 비해 간단하지만 현재의 위치 파악이 중요해 상대적으로 복잡한 특징을 지니고 있다.

좋은 웹페이지 즐겨찾기