TIL - Python - modules&packages

11615 단어 pythonpython

# 'sys.modules'와 'sys.path'의 차이점

  • sys.modules

    • 파이썬이 불러올(import) 모듈이나 package를 찾기 위해 가장 먼저 확인하는 곳
    • dictionary 형태
    • 이전에 불러왔던 모듈과 package가 저장돼 있음
    • 새롭게 불러올 모듈과 package는 이 곳에서 찾을 수 없다.
  • sys.path

    • 파이썬이 모듈과 package를 불러올 때, sys.modulesbuilt-in modules에 이어 마지막 순서로 확인하는 곳
    • list 형태이며, 그 안의 string 요소들은 파이썬 모듈들이 저장된 경로를 나타냄
    • 만약 sys.path 에서도 불러올 대상을 찾지 못하는 경우, ModuleNotFoundError 에러를 리턴한다.
  • sys모듈을 불러올 수 있는 이유는?

    파이썬이 sys모듈을 통해 불러올 모듈과 packge를 찾는다는 걸 알아봤다. 그렇다면 sys모듈 자체는 파이썬이 어떻게 찾을 수 있을까? 이를 이해하려면 sys모듈이 위치한 경로를 알아야 한다. sys모듈은 파이썬의 내장 모듈로, 모듈의 경로 정보는 파이썬 설치 시 default 값으로 저장된 상태다. 저장된 경로를 통해 파이썬은 sys모듈을 찾아낸다.

   # 'sys'모듈 이외의 파이썬 내장 모듈을 확인하고 싶다면... 아래의 메서드를 활용하자
   
   import sys
   print(sys.builtin_module_names)

# Absolute path와 Relative path의 차이점

  • Absolute path(절대 경로)

    • 절대 경로는 import가 이뤄지는 경로와 상관없이 항상 경로가 동일하다.
    • 절대 경로는 current directory(현재 프로젝트의 경로)부터 시작된다.
    • 일반적으로 local package를 import 할 때는 absolute path가 사용된다.
    • 입력한 경로의 길이가 길어지는 단점이 있다.
    • 웬만하면 Absolute path 사용이 권장된다.
  • Relative path(상대 경로)

    • 현재 프로젝트의 최상단 디렉토리가 아닌 import 하는 위치를 기준으로 경로를 정의한다.
    • 일반적으로 local package 안에서 다른 local package를 import 할 때 사용된다.
    • dot(.): import가 선언되는 파일의 현재 위치를 의미
    • dot2개(..): 현재 위치에서 상위 경로로 이동
    • 경로의 길이가 줄어드는 장점이 있지만, 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있다.

# main module에서 패키지 모듈을 import할 때 주의할 점

  • 아래 이미지와 똑같은 구조의 프로젝트 폴더를 생성해보자. main.pymain module에 해당하며, 패키지 폴더 calculator는 내부에 add_and_multiply.py 모듈과 multiplication.py 모듈을 갖고 있다.

  • 각각의 파일 내용은 다음과 같다.
    # main.py
    # absoulte path
    # from calculator.add_and_multiply import add_and_multiply 
 
    # relative path
    from .calculator.add_and_multiply import multiplication
 
    if __name__ == '__main__':
        print(add_and_multiply(1,2))
        
    # 결괏값: ImportError: attempted relative import with no known parent package

    # 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
    # add_and_multiply.py
    def multiply(a,b):
        return(a*b)
  • 위에서 main module에 해당하는 main.py는 calculator패키지의 모듈을 import해서 실행시키고 있지만, error로 인해 코드가 정상 처리되지 않고 있다. error의 발생 원인은 경로 설정과 관련 있는데, 자세한 이유는 python 공식 문서를 통해 짐작할 수 있다.

    Since the name of the main module is always "main", modules intended for use as the main module of a Python application must always use absolute imports.

  • 공식 문서에 따르면, main module에서 module을 불러와서 사용하려면 반드시 절대 경로를 사용해야 한다. 그 이유는 상대경로의 특성과 관련이 있다. 상대경로import가 이뤄지는 위치를 기준으로 경로를 정의하는데, 모듈을 스크립트에서 직접 실행하면(__name__ == __main__이 되면) 모듈의 이름이__main__이 되면서 상대경로의 기준점이 바뀌게 된다.(relative import 시, 현재 모듈의 이름이 다렉토리의 기준이 되기 때문이다.) 경로의 기준점이 바뀌게 되면, 불러올 모듈을 제대로 찾을 수 없기 때문에 절대경로를 지정하여 경로의 기준점 변환에 상관없이 모듈을 import하도록 해야 한다.
    # main.py
    # absoulte path
    from calculator.add_and_multiply import add_and_multiply 
 
    # relative path
    # from .calculator.add_and_multiply import multiplication
 
    if __name__ == '__main__':
        print(add_and_multiply(1,2))
        
    # 결괏값: 5
  • if __name__ == '__main__':은 무엇을 의미할까?

    • 파이썬에서 모듈을 실행하는 방법엔 크게 두 가지가 있다. 하나는 인터프리터에서 직접 실행하는 것이고, 다른 방법은 실행할 모듈을 다른 모듈에서 import하여 실행하는 것이다.

      1. 직접 실행하는 경우

        python3 add_and_multiply.py

      2. 다른 모듈에서 import하여 실행하는 경우

        from calculator.add_and_multiply import add_and_multiply
        add_and_multiply()

    • 1번의 경우 모듈 add_and_multiply.py__name__이라는 변수에 __main__할당된다. 반면 2번처럼 import하는 경우엔 __name__ 변수에 모듈 이름인 add_and_multiply가 할당된다. 결국 if __name__ == '__main__':의 의미는 모듈을 인터프리터로 직접 실행했을 경우에만 if문 내부의 코드를 실행하라는 의미이다.

# add_and_muliply.py에서 multiply함수를 절대경로와 상대경로로 각각 import 해보기

  • 상대경로로 불러왔을 경우
    from .multiplication import multiply
    # from multiplication import multiply
 
    def add_and_multiply(a,b):
       return multiply(a,b) + (a+b)
       
   # 결괏값: ImportError: attempted relative import with no known parent package
  • 절대경로로 불러왔을 경우
    # from .multiplication import multiply
    from multiplication import multiply
 
    def add_and_multiply(a,b):
       return multiply(a,b) + (a+b)
       
   # 결괏값은 없지만, 함수가 정상적으로 실행됨

# '__init__.py' 파일의 역할

  • __init__.py는 해당 디렉터리가 패키지로 인식되도록 도와주는 역할을 한다.

  • Import할 때 경로의 총 길이 줄여주는 역할을 한다.

  • __init__.py를 활용해서 import할 수 있는 변수/함수/클래스를 제한할 수 있다.

    # __init__.py
 
    from .multiplication import multiply

    __all__ = ['multiply']
       
   # import 할 수 있는 함수를 multiply()로 제한 
    from calculator import *

    add_and_multiply()
    # multiply()
    
    # 결괏값: NameError: name 'add_and_multiply' is not defined
  • 패키지가 import 될 때 꼭 먼저 실행되어야 하는 코드들을 관리함.

좋은 웹페이지 즐겨찾기