sys.modules: 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈이다. 단순한 dictionary 입니다. 그리고 이미 import된 모듈과 package들을 저장하고 있습니다. 즉, 한번 import된 모듈과package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있습니다. 그러므로 새로 import 하는 모듈은 sys.modules 에서 찾을 수 없다.
sys.path: 파이썬 모듈들이 저장되어 있는 위치를 나타낸다. 즉 이 위치에 있는 파이썬 모듈은 경로에 상관없이 어디에서나 불러올 수 있다. sys.path는 기본적으로 list이며 string요소 들을 가지고 있다. 파이썬이 sys.path에서도 모듈이나 패키지를 못 찾으면 ModuleNotFoundError를 리턴한다.
>>> import sys
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
>>> sys.path.append("/root/mymod")
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages', '/root/mymod']
파이썬은 다음 3가지 장소를 순서대로 보면서 찾습니다.
sys.modules
built-in modules
sys.path
위에 설명한 것과 같다. sys.modules을 보고 파일이 없으면 built-in modules로 넘어간다.
파이썬에서 제공하는 파이썬 공식 라이브러리들 입니다. Built-in 모듈들은 이미 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있습니다. 만약 built-in modules에도 없을경우 sys.path로 넘어간다.
위에 설명한 것과 똑같이 마지막으로 sys.path에서 파일을 찾는다. 참고로 sys 는 파이썬에 포함되어 있는 모듈입니다. 그러므로 다음 처럼 sys 모듈을 import 해서 sys.modules와 sys.path 를 출력할수도 있고 수정 할 수 도 있다.
정리를 하자면, 파이썬은 import 하고자 하는 모듈과 package를 찾을때에 먼저 sys.modules를 보고, 없으면 파이썬 built-in 모듈들을 확인 하고 마지막으로 sys.path에 지정되어 있는 경로들을 확인해서 찾습니다.
Local package를 import 하는 경로에는 absolute path 와 relative path 가 있습니다.
Absolute path는 절대적인, 파일이 가지고 있는 고유한 경로를 사용한다.
Relative path는 상대적인, 즉 지금 위치한 곳을 기준해서 사용한다.
Relative path는 선언해야 하는 경로의 길이를 줄여준다는 장점은 있지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 있습니다. 그러므로 웬만한 경우 absolute path를 사용하는게 권장 됩니다.
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)
임포트시 에러발생
Traceback (most recent call last):
File "/Users/jacob/Library/Mobile Documents/com~apple~CloudDocs/wecode_pre_study/main.py", line 5, in <module>
from .calculator.add_and_multiply import add_and_multiply
ImportError: attempted relative import with no known parent package
에러가 발생한 이유는 상대경로는 현재 모듈의 이름에 기반하고, 메인 모듈의 이름은 언제나 "main"이기 때문에 파이썬 어플리케이션에서 메인 모듈로 사용하려고 의도한 모듈들은 필수로 언제나 절대경로 임포트를 사용해야 한다.
절대경로와 상대경로를 모두 임포트해본 결과 절대경로는 정상적으로 임포트 되었지만 상대경로는 임포트되지 않았다.
add_and_multiply.py의 부모 경로가 multiplication.py가 아니라 오류가 발생한 것을 볼 수 있다.
main 모듈을 기본 모듈로 사용하기 위해서는 상대경로를 사용해서는 프로그램을 돌릴 수 없는 거 같다.
__init__.py 파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할을 한다. 만약 game, sound, graphic 등 패키지에 포함된 디렉터리에 __init__.py 파일이 없다면 패키지로 인식되지 않는다.
※ python3.3 버전부터는 __init__.py 파일이 없어도 패키지로 인식한다(PEP 420). 하지만 하위 버전 호환을 위해 __init__.py 파일을 생성하는 것이 안전한 방법이다.