본문 바로가기
목차
Python

[Python] Ex: Relative Path Import 시 주의할 점

by ds31x 2024. 6. 4.
728x90
반응형

다음은 main script 등에서 relative path import를 사용할 때,
__name__을 기준으로 삼기 때문에 주의해야 점을 발생 가능한 문제를 예를 들어서 설명하는 문서임.

 

참고: 패키지 컨텍스트(package context)

Python 모듈이 자신이 속한 패키지 구조 내에서의 위치와 관계를 인식하는 상태를 가리킴: 이는 모듈의 __name__ 값으로 확인 가능.


예제 디렉토리 구조

my_package/
    __init__.py
    main.py
    subpackage/
        __init__.py
        module_a.py
        module_b.py

코드 예제

1. module_a.py:

# my_package/subpackage/module_a.py
def greet():
    return "Hello from module_a"

2. module_b.py:

# my_package/subpackage/module_b.py
from .module_a import greet

def greet_from_b():
    return greet()

3. main.py:

# my_package/main.py
from subpackage.module_b import greet_from_b

if __name__ == "__main__":
    print(greet_from_b())

상황 설명

  • module_a.py는 간단한 함수를 가지고 있음.
  • module_b.py는 상대 경로로 module_a를 임포트하고 있음.
  • main.pymodule_b를 import하고 함수를 호출함.

참고: __file____name__의 차이

  • __file__모듈 파일의 경로를 나타냄.
    • 예를 들어, my_package/subpackage/module_a.py__file__ 값은 이 파일의 경로가 됨.
  • __name__모듈의 이름을 나타냄.
    • 이는 모듈이 main script로 직접 실행되었는지, 아니면 다른 module에서 import되어 실행되었는지에 따라 달라짐.
    • 직접 실행된 경우: __name__ 값은 "__main__"
    • 임포트된 경우: __name__ 값은 패키지 구조를 포함한 모듈의 전체 이름(예: "my_package.subpackage.module_a")

main.py를 직접 실행하는 경우

my_package 디렉토리에서 python main.py 명령어를 실행하면:

  • main.py__name__"__main__"이 됨.
    • 원래 package context가 유지되지 않고, __main__ 이 되어버림.
  • main.py에서 from subpackage.module_b import greet_from_b 구문이 실행될 때,
    module_b__name__"subpackage.module_b"가 됨.
    • 이 경우, 자신이 어느 패키지(or module)에 속하는지를 정확히 알게 됨.
    • import로 module이 사용되는 경우, 해당 module 내부의 relative import는 문제 없이 동작. 
    • 원래의 package context가 유지됨.
  • module_b.py 내부에서 from .module_a import greet 구문이 실행될 때,
    ."subpackage"을 의미함. 따라서 module_a가 제대로 임포트됨.

잘못된 실행 방법

module_b.py를 직접 실행하려고 하는 경우:

python my_package/subpackage/module_b.py

이 경우:

  • module_b.py__name__"__main__"이 됨: 원래의 package context가 유지되지 않음.
  • 상대 경로 임포트 from .module_a import greet가 실패함.
  • 이는 .이 더 이상 subpackage를 가리키지 않기 때문임. __main__은 패키지 컨텍스트를 잃게 됨.

올바른 실행 방법

패키지 내의 모듈을 실행하려는 경우:

python -m my_package.subpackage.module_b

이 경우:

  • module_b.py__name__"my_package.subpackage.module_b"가 됨.
  • 상대 경로 임포트 from .module_a import greet가 정상적으로 작동함.

요약

  • __name__은 모듈의 이름을 나타내며, 이는 모듈이 어떻게 실행되었는지에 따라 달라짐.
  • 상대 경로 임포트는 __name__을 기준으로 동작하므로, 직접 path를 넘겨주어 실행할 때는 패키지 컨텍스트가 유지되지 않아 문제가 발생함.
  • python -m package_name.module_name으로 실행하면 모듈이 패키지의 일부로 인식되어 상대 경로 임포트가 정상적으로 작동함.

이렇게 __file__이 아닌 __name__을 기준으로 동작하는 이유는 파이썬의 임포트 시스템이 모듈의 위치와 관계없이 모듈의 이름을 기준으로 동작하도록 설계되었기 때문임.


같이 보면 좋은 자료들

https://dsaint31.tistory.com/528

 

[Python] Module Search Path and sys.path

Module Search Path and sys.path1. Module Search PathPython 에서 module을 찾는 경로 (Module Search Path)는 다음의 순서별로 우선권을 가짐.home directory of the program (main script file이 있는 위치 or python shell이 수행된 cwd)m

dsaint31.tistory.com

 


 

728x90