How import statement finds modules and packages

제갈창민·2021년 11월 8일
0

learningbook

목록 보기
17/32
post-thumbnail

a. Import search 순서

1. sys.modules
2. built-in modules
3. sys.path
-> 파이썬은 위와 같은 순서로 모듈/package를 찾음

b. sys.modules

-> 모듈이나 package를 찾기 위해 가장 먼저 확인하는 곳
-> 단순한 dict 이고, 이미 import된 모듈과 package들을 저장하고 있음(재탐색 방지 기능)
-> 새로 import 하는 모듈은 sys.modules에서 찾을 수 없음

c. built-in modules

-> 파이썬 공식 라이브러리들
-> 해당 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있음

d. sys.path

-> 가장 마지막으로 보는 장소. list이며, str요소들을 가지고 있음
-> 각 str요소들은 다음처럼 경로를 나타냄.
-> 각 경로를 one by one 확인하면서 해당 경로에 import 하고자 하는 packages가 위치해 있는지 확인함

['',
'/Users/song-eun-u/anaconda3/bin',
'/Users/song-eun-u/anaconda3/lib/python36.zip',
'/Users/song-eun-u/anaconda3/lib/python3.6',
'/Users/song-eun-u/anaconda3/lib/python3.6/lib-dynload',
'/Users/song-eun-u/anaconda3/lib/python3.6/site-packages',
'/Users/song-eun-u/anaconda3/lib/python3.6/site-packages/aeosa',
'/Users/song-eun-u/anaconda3/lib/python3.6/site-packages/IPython/extensions',
'/Users/song-eun-u/.ipython']

-> sys는 파이썬에 포함된 모듈. 아래와 같이 sys모듈을 import해서 sys.modulessys.path를 출력, 수정 할 수도 있음

import sys

print(sys.path)
print(sys.modules)

-> In other words, 파이썬은 import하고자 하는 모듈과 package를 찾을 때,
[sys.modules 확인 -(no)> python built-in 모듈 확인 -(no)> sys.path 지정 경로로 확인]
-> sys.path에서도 못 찾으면 ModuleNotFoundError 를 리턴함

e. Absolute Path & Relative Path

-> Local packageimport하는 경로에는 absolute path, relative path가 있음

  • absolute path : 절대 경로. import하는 파일이나 경로에 상관없이 항상 경로가 동일
    └── my_app
        ├── main.py
        ├── package1
        │   ├── module1.py
        │   └── module2.py -- function1
        └── package2
            ├── __init__.py -- class1
            ├── module3.py
            ├── module4.py -- class4
            └── subpackage1
                └── module5.py -- function2
    
    
    from package1 import module1
    from package1.module2 import function1
    from package2 import class1
    from package2.subpackage1.module5 import function2
    
    [linux]
    my_app/package2/subpackage1/module5.py
    [window]
    my_app\package2\subpackage1\module5.py
    [python]
    (my_app.)package2.subpackage1.module5.py
    -> 실제로는 my_app이 생략됨

-> 하지만 경로가 길어질 수 있다는 단점이 존재[relative path]를 사용하는 이유
-> 프로젝트 최상단 디렉토리가 아닌 import하는 위치를 기준으로 경로를 정의
-> 일반적으로 relative pathlocal package안에서 다른 local packageimport할 때 사용 됨

ex> package2의 module3에서 package2의 class1과 package2의 하위인 subpackage1 의
module5의 function2함수를 import 하라
# package2/module3.py
from . import class1
from .subpackage1.module5 import function2
"(.) 은 import가 선언되는 파일의 현재 위치"
"(..) 은 현재 위치에서 상위 디렉토리로 가는 경로"

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

-> relative path는 선언해야 하는 경로의길이를 줄여준다는 장점. but,
-> 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 존재

-> 그러므로 웬만한 경우 absolute path를 사용하는 것을 권장

Assignment

1. sys.modulessys.path 의 차이점

(1) 파이썬이 모듈/package를 찾을 때 sys.modules가 첫번째, sys.path를 마지막으로 찾는다.
(2) sys.modules는 dict, sys.path는 list의 형태를 갖는다.

2. sysimport 해야하는 모듈인데, 파이썬은 sys모듈의 위치를 어떻게 찾을 수 있을까?

(1) 'sys`는 파이썬에 포함된 모듈이다.

3. Absolute pathrelative path 의 차이점

(1) `Absolute path`	
    - import하는 파일이나 경로에 상관없이 항상 경로가 동일
    - 프로젝트 최상단 디렉토리가 아닌 import하는 위치를 기준으로 경로를 정의
(2) `Relative path`
    - 선언해야 하는 경로의길이를 줄여준다는 장점
    - 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점

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


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

  
"multiplication.py"
def multiply(a,b):
    return(a*b)

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

(1) 메인이 되는 모듈의 이름은 항상 "__main__" 이기 때문에, 메일 모듈로 사용될 목적의 모듈들은
반!드!시! "절대 임포트"를 사용해야 한다. --파이썬 공식 문서에서 발췌

6. add_and_multiply.py에서 multiply함수를 절대경로와 상대경로로 각각 임포트 해보고 main모듈과의 차이점 서술(결과 포함)

(1) relative path
    - 해당 파이썬 모듈 구동 시, 자동으로 main 모듈로써 인식을 하면서 
    모듈의 name이 바뀌기 때문에 경로를 찾지 못함.

(2) absolute path
    - 상대 경로일때와 같은 에러 메세지가 아니라서 그 이유를 찾아 헤맸지만, 정확한 이유는 찾지 못함. 
      메세지의 내용과 그나마 모은 정보를 취합해보자면, calculator 하위 디렉토리에서 
      또 다시 calculator 라는 모듈을 찾으려고 하는 것 같아 보임. 
      당연히 그런 모듈은 없으므로 에러 발생.


-> 과제를 이해하기에 따라서 과제 수행 방식이 두 가지로 갈라지는데,
(1) add_and_multiply.py 내부에서 Run 했을 때 상대 & 절대경로 간의 차이점
(2) add_and_multiply.py 에서 경로를 상대 or 절대로 바꾼 다음, main.py 로 이동해서 Run 했을 때 어떤 반응이 있는지 확인하기

-> 필자가 수행한 방법은 (1)이고, (2) 방식대로 수행했을 때의 결과는 두 경로 모두 잘 실행되었음.

--> 요점은 main이 되는 모듈을 구동할 때 해당 모듈의 name__main__으로 변경되기 때문에,
relative pathmain이 되는 모듈에서 사용할 수 없다는 것,
그 외 다른 모듈에서는 relativeabsolutemain이 되지만 않는다면 잘 구동됨.

--> 결론, absolute path를 애용하자. 땅땅!

7. __init__.py파일의 역할에 대해서 정리

-> __init__.py란 폴더(디렉터리)가 패키지로 인식되도록하고, 패키지를 초기화하는 역할을 함.
     즉, 임포트로 패키지를 가져오면 __init__.py 파일이 실행되므로 이 파일에서
from . import모듈 형식으로 현재 패키지에서 모듈을 가져오게 만들어야 함.
※   참고로 python3.3 버전부터는 init.py 파일이 없어도 패키지로 인식한다(PEP 420).
      하지만 하위 버전 호환을 위해 init.py 파일을 생성하는 것이 안전한 방법이다.
-> __init__.py 파일 사용 예시

# app/a.py
from Module import test
# app/b.py
from Module import test

-> init.py 적용
  init.py 파일에 한번만 정의해 두면 해당 디렉토리에서 test라는 함수를 공통적으로 사용할 수 있음
# app/__init__.py
from Module import test
profile
자기계발 중인 신입 개발자

0개의 댓글