[Python] How import statement finds modules and packages

kimkrh·2022년 2월 2일
1

Python

목록 보기
5/14

패키지(packages) : 도트(.)를 사용하여 파이썬 모듈을 계층적(디렉터리 구조)으로 관리할 수 있게 해준다.
ex) 모듈 이름이 A.B인 경우에 A는 패키지 이름, B는 A패키지의 B모듈이 된다.
모듈(modules) : 파이썬에서 모듈은 하나의 .py 파일이다.

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

1-1. sys (system-specific parameters and functions)

sys는 파이썬에서 제공하는 모듈로, os모듈안에 있으며 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈입니다. C언어로 작성되어 있고 sys는 built-in 되어 있으므로 bulit-in modules에서 찾을 수 있습니다.

파이썬은 다음 3가지 장소를 순서대로 보면서 module/package를 찾습니다.
1. sys.modules
2. built-in modules
3. sys.path

1-2. sys.modules

  • 파이썬이 모듈이나 패키지를 찾기 위해 가장 먼저 확인하는 곳
  • 단순한 dictionary
  • 이미 import된 모듈과 package들을 저장하고 있다
    -> 한번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능
  • 그러므로 새로 import하는 모듈은 sys.modules에서 찾을 수 없습니다.

1-3. sys.path

  • 마지막으로 보는 장소입니다.
  • string요소들을 가지고 있는 list 입니다.
  • 파이썬은 list의 각 경로를 하나 하나 확인하면서 해당 경로에 import하고자 하는 package가 위치해 있는지 확인합니다.

    따라서 파이썬은 import하고자 하는 모듈과 package를 찾을때 먼저 sys.modules를 보고, 없으면 파이썬 built-in modules들을 확인하고 마지막으로 sys.path에 지정되어 있는 경로들을 확인해서 찾습니다.
    결국 못찾으면 ModuleNotFoundError 에러를 리턴합니다.


2. sys도 import해야하는 모듈입니다. 파이썬은 sys 모듈의 위치를 어떻게 찾을 수 있을까요?

'sys':<module 'sys' (built-in)>
-> sys모듈은 이미 built-in 되어 있기 때문에 built-in modules에서 찾게 됩니다.

3. Absolute path와 relative path의 차이점

파이썬의 built-in modulespip을 통해 설치한 외부 모듈 및 package는 일반적으로 import 하는데 큰 문제가 되지 않습니다.
built-in 모듈은 당연히 잘 찾아지고, pip으로 설치한 외부 모듈도 자동으로 site-packages라는 디렉토리에 설치가 되는데, 이 site-packages는 sys.path에 이미 포함되어 있기 때문에 찾는데 문제가 없습니다.
문제는 직접 개발한 local package입니다. 직접 개발한 local package를 import할 때는 해당 package의 위치에 맞게 import 경로를 잘 선언해야 합니다.

3-1. Absolute path

  • import를 하는 파일이나 경로에 상관없이 항상 경로가 동일
  • current directory라고 하는 현재의 프로젝트 디렉토리는 default로 sys.path에 포함되게 됩니다.
  • 경로가 길어지는 단점이 있습니다.
# Absolute path를 사용해 package1 과 package2를 import
from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2

3-2. relative path

  • 경로가 길어지는 absolute path의 단점을 보완
  • absolute path와 다르게 프로젝트 최상단 디렉토리를 기준으로 경로를 잡지 않고 import하는 위치를 기준으로 경로를 정의합니다.
    -> 일반적으로 relative path는 local package 안에서 다른 local package를 import할 때 사용됩니다.
  • 길이를 줄여주지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있습니다.
# relative path를 사용해package2의 module3에서 package2의 class1과 
# package2의 하위 package인 subpackage1의 module5의 function2 함수를 import

from . import class1
from .subpackage1.module5 import function2
# subpackage1/module5.py
from ..module4 import class4

.은 import가 선언되는 파일의 현재 위치,
..은 현재위치에서 상위 디렉토리로 가는 경로입니다.
-> 웬만한 경우 absolute path 사용 권장

4. calculator 패키지 만들기

5. main.py에서 상대경로로 add_and_mutiply를 임포트 했을 때 발생하는 에러를 확인하고, main module에서는 패키지의 모듈을 어떻게 임포트 해야할까?

ImportError: attempted relative import with no known parent package
ImportError가 발생한다. 파이썬에서 메인 모듈은 항상 절대경로를 이용하여 import 해야한다.
메인 모듈은 패키지의 메인 파일이며, 프로그램의 시작점을 말한다.
메인 모듈에는 if __name__ == "__main__" 코드를 넣어준다.
따라서 메인 모듈은 절대경로로 모듈을 불러와야 한다.

from calculator.add_and_multiply import add_and_multiply

6. add_and_multiply.py에서 multiply함수를 절대경로와 상대경로도 각각 임포트 해보고 main 모듈과 차이점을 생각해보고 결과를 출력

  # 상대경로
  from .multiplication import multiply

ImportError: attempted relative import with no known parent package

  • add_and_multiply.py 모듈 자체를 실행하는 경우에는 multiply 함수를 상대경로로 지정했을 때 main.py와 같은 오류가 발생한다. -> add_and_multiply.py가 __main__이 된다.
    즉, 모듈 자체를 실행하는 경우에는 그 모듈안에 다른 모듈을 import할 때 반드시 절대경로로 import해야한다.
	# 절대경로
	from calculator.multiplication import multiply

ModuleNotFoundError: No module named 'calculator'

  • 절대 경로를 import할때에는 현재의 디렉토리가 sys.path에 포함된다. 따라서 다음과 같은 절대경로를 설정하면 add_and_multiply.py 모듈 자체를 실행할 때 오류가 나지 않는다.
	from multiplication import multiply
  • 모듈이 직접 실행되는 모듈이 아닌 경우에는 상대경로 import를 허용한다. 따라서 add_and_multiply.py 모듈에 multiply 함수를 절대경로나 상대경로로 지정하고 main.py을 실행했을 때는 잘 동작한다.
    from .multiplication import multiply
    from calculator.multiplication import multiply

7. __init__.py 파일의 역할

init 파일은 해당 디렉토리가 패키지임을 알려주는 역할을 합니다.
특정 디렉토리의 모듈을 *을 사용하여 import할 때는 해당 디렉토리의 __init__.py__all__변수를 설정하여 불러오고 싶은 모듈을 정의해주어야 합니다.

0개의 댓글