이름 그대로 완전한 형태의 경로를 말합니다
import 하는 위치를 기준으로 상대적인 경로를 말합니다
Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path)
However, explicit relative imports are an acceptable alternative to absolute imports, especially when dealing with complex package layouts where using absolute imports would be unnecessarily verbose
공식문서(PEP8)에 따르면
절대 경로(absolute path)를 사용할 것을 권장합니다
다만, 같은 package 속에서 불필요하게 장황한 절대 경로라면 상대 경로(relative path)를 사용할 수 있다
고 쓰여있습니다
PEP (Python Enhancement Proposal) 링크
PEP 8 링크
my_app 이라는 project를 생성하고 여러 directory와 file을 만들었습니다
위 구조에서
main.py 에 module1.py 와 module5.py 를 절대 경로를 통해 import 해보겠습니다
# main.py
from package1 import module1
from package2.subpackage import module5
절대 경로로 import 시 my_app 은 생략된 것을 볼 수 있습니다. my_app이 시작점(entry point) 이기 때문입니다.
절대 경로로 import 시 시작점은 project directory 입니다
my_app 이라는 project를 생성 시 자동으로 sys.path에 요소에 추가되었기 때문에 my_app directory가 시작점으로 설정되는 것 입니다
project directory생성 시 자동으로 sys.path에 요소로 추가됩니다.
import search flow 링크
상대 경로를 설명하기 위해 my_app directory에 new_module.py를 추가했습니다
module4에서
현재 directoty의 module4.py 와
하위 directory인 subpackage의 module5.py와
상위 directory의 new_module.py 를 import해보겠습니다
# module3.py
from . import module4
from .subpackage import module5
from .. import new_module
import 하는 file의 directory를 시작점으로 잡습니다.
따라서 package2를 시작점으로써, .(Dot)을 통하여 directory를 이동합니다
Dot 갯수별 directory 위치
하지만 PEP 8에 나와있듯, 상대 경로로 import하는 것은 지양해야합니다.
특히나 상대 경로로 import 했을때 생기는 문제점은
file 위치가 변경된다면 경로도 다시 지정해야 하기 때문입니다!
__init__.py
file의 역할구조를 보면 __init__.py
file이 보입니다.
__init__.py
은 해당 directory가 package 임을 알려주는 역할을 합니다.
class 선언 시 __init__
는 magic method로써 사용되며, instance의 초기화를 진행해 주는 역할을 수행합니다
마찬가지로 __init__.py
은 directory 수준(level)에서도 package의 초기화 역할을 수행합니다
import 할때 경로의 총 길이 줄여줄 수 있고
package에서 import 할 수 있는 변수, 함수, 클래스를 제한할 수 있습니다
Python3.3 버전부터는
__init__.py
file이 없어도 패키지로 인식하지만 하위 버전 호환을 위해__init__.py
file을 생성하는 것이 안전한 방법입니다.
직접 실행(run) 하는 module 에 적히는 import 경로는 제약사항이 존재합니다
제약사항을 알아보기위해 실습을 해보겠습니다.
보통 main.py 에서 직접 실행하기 때문에
main.py 에서 import 를 절대 경로로 했을때와 상대경로로 했을때
어떤 일이 발생하는지 알아보겠습니다.
C:\Users\jigiseong\PycharmProjects\velog\venv\Scripts\python.exe C:/Users/jigiseong/PycharmProjects/velog/main.py
5
Process finished with exit code 0
main.py 에서 절대 경로로 import 하고 직접 실행하면 정상적으로 실행됩니다
위치를 모두 때려 박으니 당연히 정상작동 하겠죠?
아래의 도식처럼 . velog 라는 directory에서
C:\Users\jigiseong\PycharmProjects\velog\venv\Scripts\python.exe C:/Users/jigiseong/PycharmProjects/velog/main.py
Traceback (most recent call last):
File "C:\Users\jigiseong\PycharmProjects\velog\main.py", line 5, in <module>
from .calculator.add_and_multiply import add_and_multiply
ImportError: attempted relative import with no known parent package
Process finished with exit code 1
ImportError: attempted relative import with no known parent package
main.py 에서 상대 경로로 import 하고 실행하면
알려진 상위 패키지가 없는 상대 가져오기 시도라는 importError 가 발생합니다.
(즉 entry point가 velog가 아닌 것 입니다)
"main.py는 velog 패키지 맞는데;; 외않되;;;"
"__main__"
이 되기 때문입니다공식문서에 따르면
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.
https://docs.python.org/3/tutorial/modules.html#intra-package-references
- 결론만 축약해보자면
"직접 실행할 module에서는 항상 절대 경로로 import 해야한다" 입니다
이유를 알기 위해선
__name__
이 존재하는 것과module은 미리 정의된 속성:
__name__
을 갖습니다
https://docs.python.org/3/reference/datamodel.html#special-method-names
The__name__
attribute must be set to the fully-qualified name of the module.
This name is used to uniquely identify the module in the import system.
https://docs.python.org/3/reference/import.html#import-related-module-attributes
위에서 언급한 이유를 순번에 맞춰 서술해 봤습니다.
module은 미리 정의된 속성으로 __name__
속성이 존재합니다. __name__
속성에 에 module 의 이름을 저장합니다.
근데 직접 실행하는 module은, 이름이 __main__
이 저장 됩니다. 즉 __name__
= "__main__"
이 할당됩니다
상대 경로는 해당 속성을 통해 (__name__
변수에 할당된 문자열을 통해) 위치를 파악하여 경로를 계산합니다
즉, 직접 실행되는 module은 원래의 위치가 아닌
"__main__"
에 해당하는 위치로 계산되기 때문에 상대 경로를 쓸 수 없는 것 입니다!
"위치를 바꿔놓고 예전 위치를 기준으로 경로를 써두니 될리가 없겠죠?"
jiggyjiggy : "a야, 우측으로 1칸, 아래로 1칸 이동하면 누가있지?"
a: "f가 있지"
jiggyjiggy : "a야, 우측으로 1칸, 아래로 1칸 이동하면 누가있지?"
a: "아무도 없지;;"
직접 실행되지 않는 module에서의 import 경로는 절대경로, 상대경로 상관 없습니다.
직접 실행되지 않았기 때문에 __name__
속성이 변경되지 않기 때문이겠죠? ㅎㅎ
하지만 PEP 8에서 언급했듯,
상대경로는 file의 위치가 변한다면 바뀌는 경로이기 때문에 절대 경로로 쓰는 것이 좋은 습관입니다
Python code를 보다보면
if __name__ == '__main__':
를 자주 접하셨을 겁니다
import 했는데 해당 파일에 함수 호출이 있다면 그대로 실행됩니다
링크로 빼 링크