파이썬에서 모듈이나 패키지를 찾을 때 다음과 같은 순서로 찾습니다.
sys.modules
import
된 모듈이나 패키지를 저장하는 곳, 즉 한번 import
된 모듈이나 패키지를 파이썬이 다시 찾지 않아도 된다.import
하는 모듈은 sys.modules
에서 찾을 수 없다.built-in modules
우리가 그냥 꺼내 쓰는 함수들은 이미 구현되있는 파이썬 라이브러리이다.
sys.path
string
요소들을 가지고 있는 list
형태list
를 하나하나 확인하면서 원하는 모듈과 패키지를 확인참고: sys
는 파이썬이 가지고 있는 모듈이다. 그러므로 sys
모듈을 import
해서 sys.modules
와 sys.path
를 출력하거나 수정할 수 있다.
import sys
print(sys.modules)
print(sys.path)
결론적으로 파이썬은 위와 같은 순서로 모듈이나 패키지를 검색한다. 하지만 이 3개의 경로에서 찾지 못한다면 ModuleNotFoundError
를 출력한다.
Absolute Path
는 가장 최상위 디렉토리부터 검색을 시작한다. 그렇기 때문에 현재 어느 디렉토리에서 검색을 하든 항상 경로가 동일하다.
참고로 current directory 라고 하는 현재의 프로젝트 디렉토리는 default로 sys.path 에 포함되게 됩니다.
일반적으로 local package
를 import
할 때는 absolute path
를 사용하면 된다. 하지만 absolute path
를 사용할 때 단점은 항상 최상위 디렉토리부터 검색하기 때문에 경로가 길어질 수 있다는 것이다.
이러한 단점을 보완하기 위해 relative path
를 사용한다.
여기서 local package
란 Built-in module
과 pip
를 통해 설치한 외부 모듈이 아닌 직접 개발한 모듈의 패키지를 말한다.
absolute path
와의 차이점은 import
할 때 최상위 디렉토리부터 검색하는 것이 아니라 import
하는 위치를 기준으로 경로를 설정한다.
일반적으로 local package
안에서 다른 local package
를 import
할 때 사용된다.
# package2/module3.py
from . import class1
from .subpackage1.module5 import function2
여기서 닷 .
은 import
가 선언되는 현재 파일 위치를 나타낸다.
닷 2개..
는 현재위치에서 상위 디렉토리로 가능 경로이다.
relative path
는 경로의 길이를 줄여준다는 장점이 있지만, 헷갈리기 쉽고 파일 위치가 변경되면 경로도 바꿔야 되는 단점이 있다. 그러므로 웬만하면
absolute path
를 사용하는 것이 권장된다.
Path(경로)에 대한 예제를 한번 풀어보자.
calculate
패키지 만들기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)
2.main.py
에서 상대경로로 add_and_mutiply
를 임포트 했을 때 발생하는 에러를 확인하고, 다음의 파이썬 공식 문서를 참고해서 main module 에서는 패키지의 모듈을 어떻게 임포트 해야하는지 블로깅 해주세요.
https://docs.python.org/3/tutorial/modules.html#intra-package-references
우선 위 문제대로 실행하게 되면 다음과 같은 오류창이 뜬다.
# ImportError: attempted relative import with no known parent package
import 에러고 부모 패키지를 알수 없다고 한다.
위의 공식문서를 참고해서 에러를 해결해보자.
Note that relative imports are based on the name of the current module. 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.
해석해보면 상대 import 는 현재 모듈의 이름을 기반으로 합니다. 주 모듈의 이름은 항상 "__main__" 이므로 python 애플리케이션의 주 모듈로 사용하려는 모듈은 항상 절대경로로 import 해야합니다.
그렇기 때문에 main.py 에서 다른 경로의 모듈,패키지,함수,클래스를 사용할려면 항상 절대 경로를 사용해야한다는 뜻입니다.
add_and_multiply.py
에서 multiply함수
를 절대경로와 상대경로도 각각 임포트 해보고 main 모듈과 차이점을 생각해보고 결과를 출력해 보세요.from .multiplication import multiply
# from calculator.multiplication import multiply
def add_and_multiply(a, b):
return multiply(a, b) + (a+b)
# ImportError: attempted relative import with no known parent package
일단 add_and_multiply.py
에서 상대경로로 multiply
의 함수를 import
하면
ImportError: attempted relative import with no known parent package
에러 메세지가 출력된다. main.py
에서 봤던 에러랑 같은 에러가 출력된다.
마찬가지로 main module
인 add_and_multiply.py
의 위치를 잡지 못해 발생한 에러이다. 절대경로로 바꿔준다면 문제없이 실행이 된다.
같은 패키지 내에 모듈에서 다른 모듈의 기능을 사용하고 싶다면 사용하고 싶은 모듈의 이름을 바로 import
해주면 된다.
____init____.py
의 역할____init____.py
의 역할은 해당 디렉토리가 파이썬의 패키지라는 것을 알려준다. 패키지를 초기화하는 역할도 한다. python3.3
이상부터는 ____init____.py
이 없더라도 패키지로 인식되지만 하위버전과 상위버전의 호환을 위해 ____init____.py
파일을 만들어 주는 것을 권장한다. ____init____.py
파일 안에는 내용을 기본적으로 비워두면 된다.
all
from <모듈 이름> import *
*
은 해당 모듈의 모든 기능을 사용하겠다는 의미이다. 하지만 from + <모듈이름>을 적어줄 떄 from 모듈이름.모듈이름.모듈이름
의 양식으로 작성한다.
하지만 위의 양식에서 루트 디렉토리-> 서브 디렉토리 -> 모듈의 순으로 들어가게 되는데
from 루트디렉토리 -> 서브디렉토리 import *
하게 되면 해당 기능을 사용할 수 없다. 서브디렉토리안의 모듈이 있더라도 어느 모듈의 기능을 사용하고 싶은지 인식하지 못하기 때문에 기능을 사용하고 싶은 서브디렉토리의 ____init____.py
파일에서 기능을 사용하고 싶은 모듈을 all
로 정의 해줘야한다.
__all__ = ['모듈 이름']
이것의 ____init____.py
의 두 번째 기능이다.
상대 경로 문제 피해가기는 다음의 링크를 참조해보자
https://blog.potados.com/dev/python3-import/