Python | Sys modules

celeste·2022년 4월 4일
0

Replit) Python Basic

목록 보기
9/10
post-thumbnail

Python Replit 57. How import statements finds modules and packages

What is Sys?

SYS(System-specific parameters and functions) 인터프리터에 의해서 사용되거나 관리되는 변수와 함수에 대한 접근을 항상 제공하는 모듈이다.

쉽게 말하면,
sys는 파이썬에 포함되어 있는 모듈로,
sys 모듈을 import해서 sys.modulessys.path 를 출력할수도 있고 수정 할수도 있다.

파이썬이 모듈/package를 찾는 3가지 방법

🍄 Import Search 순서 🍄

1. sys.modules
2. built-in modules
3. sys.path

  1. sys.modules에서 import에 명시 된 모듈을 찾아본다.
  2. 없을 경우 python built-in modules을 확인한다.
  3. 없을 경우 sys.path에 지정 되어 있는 경로들을 하나 하나 확인한다.
  4. sys.path에도 없을 경우 ModuleNotFoundError 에러를 리턴

🗃sys.modules

  • 파이썬이 모듈/패키지를 찾기위해 가장 먼저 확인하는 곳
  • dictionary 형태
  • 이미 import된 모듈과 package들을 저장하고 있음 → 한번 import 되면다시 찾지 않아도 됨
  • 장점:
  • 단점: 새로 import 하는 모듈은 sys.module에서 찾을 수 없다

🗃built-in modules

  • 파이썬에서 제공하는 공식 라이브러리
  • 장점: 파이썬에 포함되어 나오므로 쉽게 찾을 수 있음

📃sys.path

  • list 형태 (string 요소들을 가지고 있는 list)
    • 각 string 요소들은 경로를 나타낸다.
['',
 '/Users/song-eun-u/anaconda3/bin',
 '/Users/song-eun-u/anaconda3/lib/python36.zip',
 '/Users/song-eun-u/anaconda3/lib/python3.6',
 '/Users/song-eun-u/anaconda3/lib/python3.6/lib-dynload',
 '/Users/song-eun-u/anaconda3/lib/python3.6/site-packages',
 '/Users/song-eun-u/anaconda3/lib/python3.6/site-packages/aeosa',
 '/Users/song-eun-u/anaconda3/lib/python3.6/site-packages/IPython/extensions',
 '/Users/song-eun-u/.ipython']
  • 파이썬은 위 list의 각 경로(요소)를 하나 하나 확인하며 해당 경로에
    import하고자 하는 패키지가 어디에 있는지 확인한다.

Absolute path와 relative path의 차이점

모듈을 불러올(import) 때:

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

2) 그럼 문제는: 직접 개발한 local packages
↦ 직접 개발한 local packages를 import할 때는 absolute path일 것이냐, relative path로 할 것이냐의 선택의 기로에 놓이게 된다
일반적으로 local package를 import할 때는 절대경로를 사용할 것이 권장되어진다.

Absolute path

🚀 특징:

  • 루트 디렉토리(최상단 디렉토리)에서 시작
  • import하는 파일이나 경로에 상관없이 경로가 항상 동일하다.
    (current directory라고 하는 현재의 프로젝트 디렉토리는 자동으로 sys.path에 포함되게 된다.)

👍 장점: 어디에서든 접근 가능한 경로 지정 방식 (프로젝트 내에서 어느 파일, 어느 위치에서 import 하던지 경로가 동일)
👎 단점: 경로가 길어질 수 있다

Relative path

🚀 특징:

  • import하는 위치 기준
  • 그래서 일반적으로 로컬 패키지 안에서 다른 로컬 패키지를 import할 때 사용하는 것

👍 장점: 길이가 절대경로보다 짧다
👎 단점: 현재 위치가 달라지면 경로가 다르다

EX)

# 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를 임포트 한다는 것

실습: calculator 패키지 만들기

Assignment

앞으로 개발하면서 많은 패키지를 사용할 것이고 만들어야 하는 경우도 있을 수 있기 때문에 이번과제는 직접 패키지를 만들어 보는 과제 입니다.

로컬 환경에서 파이썬을 설치하고 진행해 주세요.

디렉토리 구조는 다음과 같고 각 파일의 코드내용은 다음과 같습니다.

__init__.py 파일에는 아무코드도 없지만 init 파일은 해당 디렉토리가 패키지임을 알려주는 역할을 합니다.

➤ Python에서 각각의 파일을 만들고, calculator 라는 폴더도 만들어서 해당되는 파일을 넣어줬다.

상대경로로 add_and_multiply import

main.py에서 상대경로로 add_and_multiply를 import했을 때 발생하는 에러

에러를 잘 해석해본다:
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를 하여야 한다.

absolute path를 써야하는데 relative path를 써서 문제가 된것 같다.

파이썬에서 상대경로로 import할 때는 기준점을 잡기 위해 __name__ 변수를 이용한다. __name__ 변수는 모듈의 이름을 저장하고 있는데,

main.py 파일에서 조건문 if __name__ == '__main__':의 의미는 현재 모듈이 main module(=시작점)일 경우에 조건을 실행하라는 뜻으로,

-m 모듈이름 명령어는 해당 모듈을 sys.path에서 검색하고 그것을 main module로 실행하라는 의미이다.

main 모듈이 있는 프로젝트 폴더 외부에서 main 모듈의 경로를 명시한 뒤 실행하면 에러 없이 결과값이 나온다.

🔑 absolute path로 수정해주면 문제 없이 출력된다

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

상대경로로 add_and_multiply import

처음 주어진 add_and_multiply.py 파일은 다음과 같다

from .multiplication import multiply

from calculator.multiplication import multiply

처음 주어진 add_and_multiply.py 파일은 다음과 같다

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라고 치면 에러 없이 실행이 된다.

init.py 파일의 역할은?

__init__.py

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

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

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

0개의 댓글