TIL. 21 - 파이썬 Modules & Packages (import, init, sys, path)

문승준·2021년 9월 7일
0

Python

목록 보기
8/8

1-1. 모듈, 패키지, PSL

  • 모듈 : 변수나 함수, 클래스 등을 모아놓은 .py 파일

  • 패키지 : 디렉토리에 특정 기능별로 모듈을 모아둔 것.

    패키지는 모듈에 네임스페이스를 제공한다.

  • 파이썬 표준 라이브러리 : 기본으로 설치된 내장함수, 모듈, 패키지들을 PSL 이라 부른다.

" 다른 파일에서도 재사용이 가능하게하고,
전체 코드가 너무 커졌을때 여러 파일로 나누어 정리하는 것 "


1-2. 모듈 가져오고 사용하기

import

  • import 모듈1, 모듈2.함수/변수/클래스

  • 사용시 모듈2.함수() 처럼 모듈명을 적어줘야 네임스페이스를 찾을 수 있다.

from ... import ...

  • from 모듈이름 import 함수/변수/클래스1, ... , 함수/변수/클래스N

  • 사용시 모듈명이 없어도 바로 호출할 수 있다.

from ... import *

  • 해당 모듈의 모든 요소 가져오기

  • local scope를 가진 다른 객체들과 이름 충돌이 일어날 수 있다.

from ... import ... as ...

# as로 새로운 이름을 주어 사용하기 (모듈 이름도 가능)

from my_module  import my_func as f1
from my_module2 import my_func as f2
from my_module3 import function_with_name_too_long as f3

f1()
f2()
f3()
  • 위의 예시처럼 다른 모듈에 동일한 이름의 함수가 존재할 수도 있고,
    모듈이나 다른 요소의 변수명이 너무 길면 줄여줄 수 있다.

1-3. 패키지 가져오고 사용하기

import

  • dot notation으로 원하는 모듈을 골라서 가져오면 된다.
import pkg.mod1
from pkg.mod2 import func2

pkg.mod1.func2()
func2()

__init__.py

  • package가 import될때 자동으로 실행된다.

  • __init__.py 파일이 하는 역할
    1. Import 할때 경로의 총 길이 줄여주기
    2. Package에서 import 할 수 있는 변수/함수/클래스 제한하기
    3. 그 외 package가 import될때 꼭 먼저 실행되어야 하는 코드들
    4. 위치한 디렉토리가 package임을 알려준다.

1. Import 할때 경로의 총 길이 줄여주기

# main.py
import pkg.mod1

pkg.mod1.func2()

# func2 함수의 경로(패키지, 모듈)를 매번 입력해줘야한다.
  • __init__ 파일에 먼저 import 해준다.
# __init__.py
from .mod1 import func2

# .은 현재 디렉토리를 의미
  • 함수의 경로를 줄여준다.
# main.py
from pkg import func2

func2()

2. Package에서 import 할 수 있는 변수/함수/클래스 제한하기

  • __all__ 변수 지정하기

    default 값은 모든 함수/변수/클래스이다.
    -> 사용을 원하는 요소들을 string으로 list에 지정한다.

# __init__.py

from .mod1 import func2
from .mod2 import func3

__all__ = ['func2', 'func3'] # 사용하고 싶은 함수 2개 지정
# main.py

from pkg import *

func2()
func3()
func4() ## <== Error.

# func4 함수는 __all__ 에 정의되지 않았으므로 import 될 수 없음.

다른 package 설치하기 (pip)

  • pip : 파이썬의 package manager

  • 파이썬 설치시 같이 설치되며

    pip install Django


1-4. import 의 작동원리

  • Import Search 순서

    1. sys.modules

    2. built-in modules

    3. sys.path

1. sys.modules

  • 모듈이나 패키지를 찾기위해 가장 먼저 확인하는 곳.
  • 이미 import된 모듈과 패키지들을 저장하고 있는 딕셔너리.
  • 새로 import하는 경우 sys.modules에서 찾을 수 없다.

2. built-in modules

  • 파이썬 공식 라이브러리들
  • 이미 파이썬에 포함되어 있다.

3. sys.path

  • 경로를 나타내는 string 요소들을 가지고 있는 list

  • 만들어지는 과정

    1. 최초 실행된 py파일의 위치 디렉토리를 추가한다. (interactive shell로 실행하면 '' 빈스트링)

      → 어디서 실행했느냐가 아니라 어디에 위치하느냐.

    2. 환경 변수의 PYTHONPATH 값을 가져와서 추가한다.

    3. OS나 Python 배포판이 설정해 둔 값을 추가한다.

['',
 '/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']
  • sys 는 파이썬이 설치될때 함께 설치되는 라이브러리 built-in모듈이다.

    built-in modules 부분에서 찾을 수 있다.

  • sys 모듈을 import 해서 sys.modulessys.path 를 출력할수도 있고 수정 할 수 있다.

import sys

print(sys.modules) # 이미 import된 것들을 저장
print(sys.path) # 경로들을 나타낸다.

sys.path 에서도 못찾으면 ModuleNotFoundError 에러를 리턴한다.


1-5. Absolute Path & Relative Path

  • built-in 모듈pip 으로 설치한 외부 모듈은 import에 크게 문제없다.

    site-packages 라는 디렉토리에 설치되고, sys.path 에 이미 경로가 포함되어 있기 때문이다.

  • 직접 개발한 로컬 패키지는 import 경로를 잘 선언해야한다.

absolute path

  • import 하는 파일이나 경로에 상관없이 항상 동일한 절대 경로.

  • 프로젝트 최상단 디렉토리를 기준으로 한다.

    current directory 경로는 default로 sys.path 에 포함되서 생략 가능

  • 보통 local package를 import할때 주로 사용한다.

  • 경로의 길이는 길지만 명확하게 경로를 보여준다.

relative path

  • import하는 위치를 기준으로 하는 상대적인 경로

  • local package 안에서 또다른 local package를 import할때 사용한다.

  • 경로의 길이를 줄여주지만, 헷갈리기 쉽고 파일 위치가 변경되면 경로도 변경해야한다.

절대 경로, 상대 경로 예시

└── my_app
    ├── main.py
    ├── package1
    │   ├── module1.py
    │   └── module2.py
    └── package2
        ├── __init__.py
        ├── module3.py
        ├── module4.py
        └── subpackage1
            └── module5.py
  • 절대경로 - subpackage1module5function2를 import하고 싶을때
# main.py

from package2.subpackage1.module5 import function2

# my_app.package2.subpackage1.module5.py -> 전체 경로 위치
# my_app 디렉토리는 생략 가능
  • 상대경로 - package2module3에서

    package2class1subpackage1module5function2 함수를 Import할때

# package2.module3.py

from . import class1

from .subpackage1.module5 import function2

-> dot . 은 import가 선언되는 파일의 현재 위치를 나타내고, .. 두 개는 상위 디렉토리


1-6. Intra-package References

import로 패키지 가져오기

  1. main.py에서 calculator 패키지의 add_and_mulitply 모듈을 import하는 경우
  • 절대경로 → 정상 작동

    from calculator.add_and_multiply import add_and_multiply

  • 상대경로

    from .calculator.add_and_multiply import add_and_multiply

ImportError: attempted relative import with no known parent package 에러가 나온다.

  • 도대체 왜?

    파이썬의 스크립트 (파일, 모듈 등)가 실행되는 2가지 방법은
  1. 인터프리터에서 파일자체를 직접 실행

    -> 직접 실행되는 파일에서 __name__ 은 무조건 __main__이다.

  2. 다른 파일에서 import 되어서 실행

    -> 진정한 의미의 모듈이며 __name__해당모듈이름이다.

메인파일 실행 뒤 상대경로를 통해 다른 모듈을 import 할때,
파이썬은 모듈의 이름(__name__)에 기반을 두고 현재모듈의 위치를 찾는다.

따라서, 이름이 __main__으로 바뀐 파일(모듈)은 파이썬이 위치를 찾을 수 가 없다. 상대경로의 출발점이 되는 위치를 못찾아 위와 같은 에러가 발생하는 것이다.

  • 결론적으로 __name__ == __main__ 이 되는 시작 스크립트 (main.py)에서는 절대경로 방식으로 import해야한다.

문서 참조
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://velog.io/@hamsterhamin/Python-ImportError-attempted-relative-import-with-no-known-parent-package


  1. add_and_multiply.py 에서 multiplication 모듈의 multiply 함수를 import 하는 경우
  • 절대경로 → calculator 패키지를 못 찾는다

    from calculator.multiplication import multiply

  • 상대경로 → calculator 패키지를 못 찾는다

    from calculator.multiplication import multiply

from .multiplication import multiply 로 하면 정상 작동된다.
→ 동일한 디렉토리에 있어서 폴더명을 빼고 상대경로로 작성한다.

  • 왜 상대경로로 작성해야 하는가?


    메인파일이 실행되고 나면 메인을 기준으로 절대경로가 잡히게 되는데, 이때 add_and_multiply는 경로내에서 calculator 패키지의 하위 모듈로 등록이 된다.


    메인모듈의 절대경로가 잡히면서 다른 모듈들을 상대적으로(Relative) 비교할수 있는 뿌리가 생긴 것이다.
  • 어떤 파일을 실행하는지에 따라 다르다. (누가 __main__ 인지)


    main.py 실행시
    add_and_multiply를 main모듈에 import할 때 절대경로를 써야한다. (상대경로 쓸 시 에러.)
    add_and_multiply에서 multiplication를 import할때 상대경로를 써주어야한다.(절대경로 쓸 시 에러.)


    add_and_multiply 직접 실행시 (얘가 메인모듈이 될때)
    multiplication를 import할때 절대경로를 써주어야한다.(상대경로 쓸 시 에러.)

여전한 의문점들
sys.path와도 연관이 있는 걸까?
sys.path에 작성된 current directory가 아니어서 그런가?
절대경로를 작성할때 current directory란?


  • 참조목록

모듈가져오기 https://wikidocs.net/29

모듈가져오기 https://dojang.io/mod/page/view.php?id=2441

sys.path https://jins-sw.tistory.com/17

sys.path https://sshkim.tistory.com/158

https://docs.python.org/3/tutorial/modules.html

https://stackoverflow.com/questions/33837717/systemerror-parent-module-not-loaded-cannot-perform-relative-import

profile
개발자가 될 팔자

0개의 댓글