1월 29, 2022

import는 어떻게 module과 package를 찾는가

1. sys.module과 sys.path 의 차이점

파이썬에서 모듈이나 패키지를 사용하기 위해선 해당 파일(모듈의 경우) 혹은 디렉토리(패키지의 경우) 가 어딨는지 파이썬이 찾을 수 있어야 import를 하여 사용할 수 있습니다. 이때 파이썬 정해진 순서에 따라 모듈 or 패키지를 찾습니다.

  1. sys.modules
  2. built-in modules
  3. sys.path
먼저, 2번의 built-in modules의 경우, 말 그대로 파이썬에서 제공하는 공식 라이브러리들을 의미합니다. 이미 파이썬에 포함돼 나오므로 파이썬이 쉽게 찾을 수 있습니다.

1번의 sys.modules는 파이썬이 가장 먼저 확인하는 곳 입니다.
sys.moudles는 이미 로드돼 있는 모듈에 이름을 mapping하는 dictionary로서, 이미 import 된 모듈과 package들을 저장하고 있습니다. 즉, sys.modules덕분에 한번 import한 모듈이나 package를 파이썬이 또 다시 찾을 필요가 없습니다. 반대로 말하자면, 새로 import 하는 모듈이나 패키지는 sys.modules에서 찾을 수 없다는 뜻입니다.
sys.modules는 강제로 다시 로드할 수 있도록 조작할 수 있습니다.
또한, Dictionary 형임에도 불구하고, 내부의 요소들을 마음대로 수정할 수는 없고, 필수적인 부분을 건들 경우 파이썬 전체에 문제가 생길 수도 있습니다. 


3번의 sys.path는 파이썬이 가장 마지막으로 보는 장소입니다.
sys.path는 기본적으로 list이며, string 요소들을 가지고 있는 list입니다.

각 string 요소들은 이처럼 특정 경로를 나타냅니다. 
파이썬은 이 list의 경로들을 하나하나 확인하면서 해당 경로에 import 하고자 하는 package혹은 모듈이 위치해 있는지 확인합니다. 

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

1
2
import  sys
print(sys.modules)

{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>
sys를 import하여 sys.modules를 print해보면 이를 알 수 있습니다. 
sys module은 built-in 돼있기에, built-in module들이 있는 부분에서 찾게 됩니다.


3. Absolute path와 relative path 차이점을 서술

  • 파이썬의 built-in 모듈과 pip를 통해 설치한 외부 모듈 및 패키지는 일반적으로 import 하는데 큰 문제가 되지 않습니다.

    Built-in 모듈은 당연히 잘 찾아지고, pip로 설치한 외부 모듈도 자동으로 site-packages 라는 디렉토리에 설치가 되는데, 이 site-packages는 sys.path에 이미 포함돼 있기때문에 찾는데 문제가 없습니다.

    문제는 직접 개발한 local package입니다. 직접 개발한 local package를 import 할때는 해당 package의 위치에 맞게 import경로를 잘 선언해야 합니다

    Local package를 import 하는 경로에는

    1. absolute path
    2. relative path

    가 있습니다

    • absolute path

      1. 이름 그대로 절대 경로입니다
      2. import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하기 때문

      예를들어,



      my_app이라는 프로젝트이며 package1과 package2 라는 2개의 package를 가지고 있습니다

      그리고 package2는 subpackage1라는 중첩 package를 가지고 있습니다

      Absolute path를 사용해 package1 과 package2를 import 하면 다음과 같습니다

      from package1 import module1
      from package1.module2 import function1
      from package2 import class1
      from package2.subpackage1.module5 import function2
      

      경로들의 시작점이 전부 my_app 프로젝트의 가장 최상위 디렉토리에서 시작하는 것을 볼 수 있습니다

      예를들어, subpackage1의 module5 모듈의 function2 함수를 import하려 거치는 경로는 아래와 같고,

      my_app => package2 => subpackage1 => module5.py

      이를 윈도우의 directory 형식으로 바꾸면

      my_app\package2\subpackage1\module5.py

      파이썬에서는 slash나 backslash(\)대신에 dot(.)을 사용해서 경로를 표현합니다

      이미 my_app 프로젝트 안에 있으므로 my_app은 생략하고 경로를 표현하게 됩니다.

      package2.subpackage1.module5.py

      이걸 from import키워드를 사용해 import 하려면 어떻게 할까요??

      from package2.subpackage1.module5 import function2

      정리하자면, my_app 프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 위와 동일하게 되므로 absolute path라고 하는 것입니다

      참고로 current directory 즉 현재의 프로젝트 디렉토리는 default로 sys.path에 포함합니다.

      그러므로 absolute path 는 current directory부터 경로를 시작하게 되는 것입니다.

      일반적으로 local pacakge를 import 할 때는 absolute path를 사용하면 됩니다.

      그러나 경로가 길어질 수 있다는 단점이 있습니다.

    • relative path

      경로가 길어지는 absolute path 의 단점을 보완하기 위해서 relative path를 사용합니다.

      Relative path는 프로젝트의 최상단 디렉토리를 기준으로 경로를 잡는게 아니라. import하는 위치를 기준으로 경로를 정의합니다.

      그래서 relative path는 local package안에서 다른 local package를 import 할 때 사용됩니다



      예를들어 package2의 module3에서 package2의 class1과 package2의 하위 package인 subpackage1의 module5의 function2 함수를 import하려고 하면??

      # package2/module3
      
      from . import class1
      from .subpackage1.module5 import function2
      

      여기서 dot . 은 import가 선언되는 파일의 현재 위치를 이야기 합니다

      현재 위치는 package2/module3.py 이므로, 현재 위치에서부터 원하는 모듈의 경로만 선언해주면 되는 것입니다

      또한 dot2개를 사용할 수도 있습니다. dot 2개 .. 는 현재위치에서 상위 디렉토리로 가는 경로입니다

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

      Relative path는 선언해야 하는 경로의 길이를 줄여준다는 장점 은 있지만

      헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점 이 있기에

      웬만한 경우 absolute path를 사용하는 것이 권장됩니다