[PythonBasic] Modules

Alex of the year 2020 & 2021·2020년 7월 6일
0

Python

목록 보기
13/18
post-thumbnail

Q1, Q2. sys.modules와 sys.path의 차이점, 파이썬은 sys 모듈의 위치를 어떻게 찾을 수 있을까?

sys.modules와 sys.path는 둘 다
파이썬이 모듈/package를 찾을 때 순서대로 찾는 곳

<참고> sys란?
파이썬에 포함되어 있는 모듈이므로 기본적으로 import 하여
'sys.modules와 sys.path를 출력하거나 수정할 수 있다

A. sys.modules
파이썬이 가장 먼저 확인하는 곳
단순한 dictionary로 이미 import된 모듈과 패키지들을 저장하고 있음 { key: value }
(한번 import된 모듈과 패키지는 파이썬이 또 다시 찾지 않아도 되도록 하는 기능)
--> 따라서 새로 import하는 모듈은 sys.modules에 없음

B. sys.path
파이썬이 가장 마지막에 확인하는 곳
기본적으로 list이며 string 요소들을 그 값으로 가짐
각 string 요소들은 예를 들어 이런 식의 경로 값

즉 이러한 list에 담긴 경로들을 하나하나 확인하며, 해당 경로에 import 하고자 하는 패키지가 있는지 찾는 것

<정리>

파이썬은 import 하고자 하는 모듈과 package를 찾을때에
먼저 sys.modules를 보고
(없으면 파이썬 built-in 모듈들을 확인하고)
마지막으로 sys.path에 지정되어 있는 경로들을 확인해서 찾음
sys.path 에서도 못찾으면 ModuleNotFoundError를 리턴

  • sys 모듈은 파이썬 기본 내장 모듈로 호출 시 바로 찾아진다.


Q3. Absolute path vs. Relative path

모듈을 불러올(import) 때:

1) 큰 문제 X: 파이썬의 built-in 모듈, pip를 통해 설치한 외부 모듈 및 package(sys.path내의 site-packages에 포함되어져있는)

2) 그럼 문제는: 직접 개발한 local packages
--> 직접 개발한 local packages를 import할 때는 absolute path일 것이냐, relative path로 할 것이냐의 선택의 기로에 놓이게 됨

  • 프로젝트명: my_app
  • packages: package1, package2
  • subpackages: package2 아래의 subpackage1

A. Absolute path(절대경로)를 이용하기
특징: import를 하는 파일이나 경로에 상관 없이 항상 경로가 동일. 순서대로만 제대로 입력하면 헷갈릴 일이 없다.

## 절대경로를 이용하여 package1과 package2를 import하는 방법

from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2

# my_app 프로젝트의 최상위 디렉토리(package1, package2)에서 시작하고 있음을 확인할 수 있다

<실제로 경로를 표현해보기>
ex. subpackage1의 module5 모듈의 function2 함수를 import 할 때,

## 리눅스 
my_app/package2/subpackage1/module5.py

## 파이썬 (dot notation)
my_app.package2.subpackage1.module5.py 

# 그런데 이 때는 이미 my_app 프로젝트 안에 있으므로 my_app은 생략한다 
package2.subpackage1.module5.py

# 위 코드를 from/import 키워드를 이용해 import 할 경우 다음과 같이 쓰게 된다
from package2.subpackage1.module5 import function2

위에서 보는 바와 같이 my_app 프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 위와 같이 동일하게 되므로 absolute path 라고 하는 것!!
그래서 일반적으로 local package를 import할 때는 절대경로를 사용할 것이 권장되어진다.
다만 한가지 이 때 안 좋은 점은 길이가 너무 길어진다는 것인데
이런 단점 보완을 위해 우리가 생각할 수 있는 것이 relative path, 상대경로이다.


B. Relative Path(상대경로)를 이용하기
절대 경로의 단점을 보완하기 위한 경로 방식이기 때문에, 이 때는 최상단 디렉토리로부터 기준 잡아 경로를 잡는게 아니라 import하는 위치를 기준으로 경로를 정의하게 된다
그래서 일반적으로 로컬 패키지 안에서 다른 로컬 패키지를 import할 때 사용하는 것

<실제로 경로를 표현해보기>
ex. package2의 module3에서 package2의 class1과
package2의 하위 package인 subpackage1의 module5의 function2 함수를 import하기

# package2/module3.py

from . import class1	# 같은 패키지의 경우 . 만 찍으면 끝
from .subpackage1.module5 import function2	
# 같은 패키지 내의 하위 패키지인 서브패키지1의 모듈5을 표현할 경우 .로 시작해서 써주기

정확히 말하면 dot(.)은 import가 선언되는 파일의 현재 위치를 이야기하는 것
dotdot(..)은 현재 위치에서 상위 디렉토리로 가는 것

# subpackage1/module5.py

from ..module4 import class4
# 이것의 의미는 현재 내가 subpackage1의 module5에 있는데,
# 한 단계 상위로 올라가서 module4로 가서 그 안의 class4를 임포트 한다는 것

Q4. Calculator 패키지 만들기


와 만들었다
🤗

1) 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))

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)

3) multiplication.py

def multiply(a,b):
    return(a*b)

Q5. main.py에서 상대경로로 add_and_multiply를 임포트 했을 때 발생하는 에러를 확인하고 main모듈에서는 패키지의 모듈을 어떻게 임포트 해야할까 고민해보기

에러를 먼저 확인해보면 이러하다

여기서 아까 저장한 main.py 를 열어본다

앗 에러~!
에러를 잘 해석해본다:
from .calculator.add_and_multiply import add_and_multiply 에서 에러가 났고, 더 정확히는
ImportError: attempted relative import with no known parent package에러이다.

상대 경로로 임포트를 시도했는데, 부모 패키지의 정의가 확실치 않다. 대략 이런 말인 것 같아서 다시
main.py를 확인한다

파이썬 공식 문서를 통해 해답을 알아본다

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 module의 이름은 실제로 언제나 'main'이기에 파이썬에서 메인 모듈로 기능하도록 프로그래밍된 모듈들은 언제나 절대경로로 import를 하여야 한다.

그래서 main.py를 이렇게 수정했다

# absoulte path
from calculator.add_and_multiply import add_and_multiply

# relative path
# from .add_and_multiply import add_and_multiply

if __name__ == '__main__':
    print(add_and_multiply(1,2))
    

그러자 출력 값은?

잘 나온 것을 확인했다
😇

Q6. add_and_multiply.py에서 multiply함수를 절대경로와 상대경로도 각각 임포트 해보고 main 모듈과 차이점을 생각해보고 결과를 출력하기

처음 주어진 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)

상대 경로로 할 것인지, 절대 경로로 할 것인지는 내가 선택하는 문제인것 같은데
우선은 상대경로(.으로 시작하는)로 먼저 세팅이 되어 있으니, 그대로 실행해봤는데
에러가 났다.

그럼 나의 선택은 이번에는 주석처리되어 있는 절대 경로 주석 처리를 풀고 절대 경로로 실행.

#from .multiplication import multiply
from calculator.multiplication import multiply
def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)

역시 에러가 난다.

지금 상대경로이건 절대경로이건 둘 다 앞에 . 혹은 calculator.를 붙이고 있는데
현재 이미 이 파일이 최상위 디렉토리인 calculaor 파일 안에 있기 때문에

패키지를 구성하는 그 최상위 파일의 이름은 import 시 생략해야 한다.
상대경로에서 .을 지우고 from multiplication import multiply라고 치면 에러 없이 실행이 된다.

Q7. init.py 파일의 역할은?

__init__.py

1) 파일 이름에서 읽을 수 있듯, initialize 즉 패키지의 시작을 알리는 코드이자
(이닛 파일이 없다면 디렉토리라고 생각할 수 있는데, 이닛이 있어서 패키지임을 알 수 있다)

2) 해당 디렉토리가 패키지의 일부임을 알려주는 역할을 한다.
다시 말해, 파일이 위치한 경로를 패키지 모듈처럼 사용할 수 있도록 해주는 중요한 기능을 수행한다. 만일 이 기능이 없다면, 모듈을 찾는 경로를 config에 설정해야만 사용할 수 있으니 번거로와진다

3) 해당 경로에 공통 사용되는 기능 및 모듈을 사용할 수 있게도 해주는데,
이 경우 Calculator 모듈에 공통으로 적용 가능한 기능이나 모듈을 포함할 수 있다.



reference:
https://webisfree.com/2017-11-06/python%EC%97%90%EC%84%9C-init-py%EC%9D%98-%EC%97%AD%ED%95%A0-%EB%B0%8F-%EC%98%88%EC%A0%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0
https://wikidocs.net/1418
https://velog.io/@ethan16/repl.it-%EA%B3%BC%EC%A0%9C23-How-Import-Statement-Finds-Modules-Packages

profile
Backend 개발 학습 아카이빙 블로그입니다. (현재는 작성하지 않습니다.)

0개의 댓글