import pyyyython
우리가 파이썬에서 특정 모듈을 import
했다고 했을 때, 파이썬은 다음과 같은 순서로 모듈을 탐색한다.
위의 순서로 우리가 import
하는 모듈을 탐색한다.
sys.module
은 이미 import
된 모듈과 여러 패키지들을 저장하고 있다.sys.module
은 파이썬이 이미 한번 import
된 모듈과 패키지를 다시 재탐색 하지 않도록 해준다.sys.module
에서 import
하지 않은 모듈을 찾을 수가 없다는 말이다.sys.path
이다. list
안에 string
형식으로 여러 경로들을 담고있다.list
요소들을 iterate
하면서 각 경로에 우리가 import
할 모듈이나 패키지가 있는지 탐색한다.sys.path
에서도 못찾으면 ModuleNotFoundError
가 발생한다.sys
모듈은 빌트인되어 있기 때문에 built-in modules에서 찾아본다.Absolute path는 프로젝트 내에서는 어느 파일, 어느 위치에서 import
하던지 경로가 동일하다. root path는 프로젝트의 최상단 디렉토리이다.
참고로 현재의 프로젝트 디렉토리는 default로 sys.path 에 포함된다. 따라서 absolute path는 현재 프로젝트 디렉토리부터 경로를 시작한다.
import
하는 파일의 위치를 기준으로 경로를 정의한다.calculator 패키지의 경로를 위 그림과 같이 설정해보자.
__init__.py
파일에는 아무코드도 없지만, 해당 디렉토리가 패키지임을 알려주는 역할을 한다.# 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))
다음을 실행해보면 이런 에러가 뜬다.
ImportError: attempted relative import with no known parent package
왜 이런 오류가 떴는지 공식 문서를 참조해보자.
파이썬 공식문서 중 PEP 328 에서 말하는 내용은 다음과 같다.
Relative imports use a module's name attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to 'main') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.
다음을 정리해보면,
relative path 의 import
는 현재 모듈의 이름 에 기반한다.
여기서 말하는 모듈의 이름이란 모듈의 __name__
속성 값을 의미한다.
만약 이 모듈의 __name__
값이 아무런 패키지 정보를 포함하고 있지 않으면 relative import 는 이 모듈이 어디에 위치하고 있던간 최상위에 있는 모듈로 인식한다.
파이썬 인터프리터는 단지 모듈명이 __main__
이라는 정보만으로는 이 모듈이 어느 위치에 있는지 알 수가 없다.
따라서 에러가 발생하는 것이다.
제일 처음 실행하는 모듈은 메인 모듈이 되며, 메인모듈의 __name__
은 항상 __main__
이다.
따라서
import
를 해야한다.# main.py
# absoulte path
from calculator.add_and_multiply import add_and_multiply
if __name__ == '__main__':
print(add_and_multiply(1,2))
위와 같이 절대경로를 이용해 import
해줄 경우, 오류 없이 실행된다.
# add_and_multiply.py
from .multiplication import multiply
# from root_calculator.multiplication import multiply
def add_and_multiply(a,b):
return multiply(a,b) + (a+b)
해당 파일 역시 다음과 같이 import error 가 난다.
ImportError: attempted relative import with no known parent package
이유는 위에서 설명한 것과 같이 relative import 를 하는 경우, 직접 실행하는 파일의 __name__
은 __main__
이기 때문에 패키지 경로를 찾을 수 없어서 에러가 난다.
마찬가지로 absoulte path 로 변경해주면 오류없이 import
를 수행한다.
python3.3 이전 :
__init__.py
파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할을 한다. 만약 위 calculator 패키지의 add_and_multiply.py 가 속해있는 디렉터리에__init__.py
파일이 없다면 해당 폴더가 패키지로 인식되지 않는다.
python3.3 이후 :
__init__.py
파일이 없어도 패키지로 인식하지만 하위 버전 호환을 위해__init__.py
파일을 생성하는 것이 안전하다.