Python - Modules & Packages

full_accel·2020년 11월 19일
0
post-thumbnail

Module과 Package

Module

module: 2. 명사 컴퓨터 모듈(특정 기능을 하는 컴퓨터 시스템이나 프로그램의 단위)

  • 파이썬에서 모듈은 Module이란 영어 단어의 뜻과 유사하게 특정 기능을 하는 함수나 변수 또는 클래스를 모아 놓은 파일이다.
  • 모듈을 사용하기 위해서 import 또는 from import을 사용한다.

Module 사용법

  • import
    • import module
    • import module1, module2, module3
  • 취향껏 이름 정해서 import
    • import module as my_module
  • module 일부만 가져오기
    • from full_module import some_class
    • from full_module import some_function
    • from full_module import some_variable
    • from full_module import some_class, some_function, some_variable
  • 투자자문을 얻기 위해 파이썬이 짜 놓은 random 모듈을 사용한 예시
from random import randrange as revelation_of_god


def god_bless_me():
    round = 6
    lottery = []
    while round != 0:
        lottery.append(revelation_of_god(1, 46))
        round -= 1
    print(f"Let the believer have light! \n {lottery}")


god_bless_me()

Let the believer have light!
[38, 14, 14, 21, 22, 6]

Package

package: 1. = parcel 2. (포장용) 상자; 포장물 3. 포장하다

  • 파이썬에서 패키지는 모듈에 대한 package(포장)이다.
  • 즉, 모듈들을 모아 놓은 것이다.
  • 모듈들이 하나의 모아놓은 최상위 디렉토리가 해당 패키지의 루트 디렉토리가 된다.
  • 패키지를 사용하는 이유는 코딩을 하다보면 모듈 하나에 담기에 코드의 양이 너무 많아서 비효율적일 수 있기 때문이다.

Package 사용법

  • import
    • import package.module
    • import package.module1, module2
  • 취향껏 이름 정해서 import
    • import package as my_package
  • module 일부만 가져오기
    • from full_package.module import some_class
    • from full_package.module import some_function
    • from full_package.module import some_variable
    • from full_package.module import some_class, some_function, some_variable

sys.modules, sys.path

sys.modules

  • sys.modules는 파이썬이 import search 중에 제일 먼저 확인하는 곳이다. (ref.)
  • sys.modules의 매핑은 이미 import된 모듈들에 대한 캐쉬처럼 동작한다.
    • 기존 import된 모듈과 패키지들을 다시 찾지 않도록 캐싱한다.
  • 그 목적이 캐싱이므로 캐싱되지 않은, 즉 새로 import하는 모듈은 sys.modules에 없다.
  • sys.modules는 dictionary 타입으로 되어 있다.
# sys.module은 파이썬이 모듈을 제일먼저 검색하는 dictionary 이다.
Python 3.8.2 (default, Jul 16 2020, 14:00:26)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.modules
{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_frozen_importlib_external': <module 'importlib._bootstrap_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>,
... (생략) ...

sys.path

  • sys.path는 모듈들에 대한 검색 경로를 특정한다.
  • sys.path는 string 타입의 리스트이다.
  • 환경변수(PYTHONPATH)로 부터 초기화 된다.
  • 프로그램의 시작시 초기화된다.
  • 리스트의 첫번째 요소 path[0]은 파이썬 인터프리터에 의해서 실행된 스크립트를 포함하고 있는 경로이다.
  • 만약 터미널에서 바로 파이썬 인터프리터를 실행한 경우 path[0]''이 되고, 파이썬에게 현재 디렉토리부터 모듈을 검색하도록 한다.
# 쉘에서 바로 파이썬 인터프리터를 실행하여 sys.path의 첫 번째 요소가 '' 인 경우
Python 3.8.2 (default, Jul 16 2020, 14:00:26)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']
>>>

파이썬이 sys 모듈의 위치를 확인하는 방법

파이썬의 import 검색 순서와 의문

파이썬은 모듈을 import하기 위해 다음의 순서대로 검색을 수행한다.

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

그런데 파이썬은 애초에 sys 모듈이 어디에 있는줄 알고 불러와서 사용하는 걸까?

파이썬은 어떻게 sys 모듈을 import하는가?

built-in modules

  • 파이썬 설치시 내장되는 모듈들
  • 위의 sys.modules의 return 값에서 (built-in)으로 표기된 모듈들은 built-in 모듈이다.
  • sys 모듈은 built-in 모듈이므로 파이썬이 built-in modules를 검색하는 과정에서 불러올 수 있다.

Absolute path와 Relative path

파이썬 공식문서를 참조하여 작성

Absolute path(절대경로)

  • 어디에서든 접근 가능한 경로 지정방식
  • 예를 들어 내 집주소를 아마존에게 알려주면 바다 건너서도 물건을 주문하여 배송받을 수 있다.
  • 절대경로를 이용한 import 예시
    • from randome import randrange

Relative path(상대경로)

  • 자기자신(파이썬 파일)의 위치를 기준으로 경로를 지정하는 방식
  • 예를 들어 편의점 위치를 알려주기 위해 "내 오른쪽에 편의점이 있다."라고 표현하는 방법
  • 상대경로를 이용한 import 예시
  • form .there import cvs

절대경로와 상대경로에 대한 파이썬의 동작

  • 상대경로로 import하는 경우 파이썬은 현재 모듈의 __name__을 기반으로 동작한다.
    • 즉, 상대경로로 import 하려면 일단 내가 누군지 알아야 하는데 이를 위해 파이썬은 __name__을 확인한다.
  • 그런데 main 모듈의 이름은 항상 __main__이기 때문에 main 모듈로써 동작할 파이썬 파일은 import 사용시에 항상 절대경로를 이용해야 한다.
    • 즉, main 모듈은 자신의 파일명과 상관 없이 자신의 이름을 항상 __main__으로 인식하므로, 자신의 이름을 기반으로 다른 파일을 찾는 상대경로 import를 사용할 수 없다.
    • main 모듈에서 상대경로 import를 사용하면 ImportError: attempted relative import with no known parent package 에러가 출력된다.

간단한 예제를 통한 확인

Absolute path와 Relative path를 알아보기 위해 간단한 예제

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

print("name of add_and_multiply.py: ", __name__)

  • multiplication.py
def multiply(a,b):
    return(a*b)


print("name of multiplication: ", __name__)

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

main.py에서 상대경로, 절대경로 import 동작

  • main.py에서 절대경로를 사용하여 실행한 경우
    • 의도한 대로 정상 동작
    • add_and_multiply.py와 multiplication.py는 자신을 이름으로 자신을 인식
# absoulte path
from calculator.add_and_multiply import add_and_multiply


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

# 실행 결과
# name of multiplication:  calculator.multiplication
# name of add_and_multiply.py:  calculator.add_and_multiply
# 5

  • main.py에서 상대경로를 사용하여 실행한 경우
    • 에러 발생: ImportError: attempted relative import with no known parent package
relative path
from .calculator.add_and_multiply import add_and_multiply


if __name__ == '__main__':
    print(add_and_multiply(1,2))
    
# 실행 결과 -> 에러 발생
# from .calculator.add_and_multiply import add_and_multiply
# ImportError: attempted relative import with no known parent package

모듈에서 상대경로, 절대경로 동작

  • import_test/calculator/add_and_multiply.py 모듈에 대해서
    • 인터프리터에서 직접 실행
    • 절대경로 import 사용
from calculator.multiplication import multiply

def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)

print("name of add_and_multiply.py: ", __name__)

# 실행 결과
# name of multiplication:  calculator.multiplication
# name of add_and_multiply.py:  __main__
  • main 모듈에 의해서 import 당하는 것이 아닌, 인터프리터로 .py 파일을 직접 실행하면 자기 자신을 main 모듈로 인식함을 확인할 수 있다.

  • import_test/calculator/add_and_multiply.py 모듈에 대해서
    • 인터프리터에서 직접 실행
    • 상대경로 import 사용
from .multiplication import multiply

def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)

print("name of add_and_multiply.py: ", __name__)

# 실행 결과
# from .multiplication import multiply
# ImportError: attempted relative import with no known parent package
  • 앞서 main.py에서 상대경로를 사용했을 때와 동일한 에러가 발생한다.
  • 이는 위에서 살펴보았듯 자기 자신을 main 모듈로 인식했고, 파이썬은 main 모듈에서 상대경로 import를 사용할 수 없도록 설계되어 있기 때문에 발생한 것이다.

__init__.py

init

initialization: 초기치 설정
initialize: 초기 내용을 설정하다

  • 많은 프로그램들에서 init는 initialization 내지는 initialize의 의미이다.
    • 예를 들어 리눅스에서 init는 시스템 초기화라는 의미에서
      • init 0는 시스템 종료
      • init 6는 시스템 재기동의 의미이다.
  • 파이썬에서도 __init__은 초기화를 의미한다.
  • 클래스에서 정의된 def __init__는 클래스로 뽑아낸 객체를 초기화하는 역할을 한다.

__init__.py의 역할

  • __init__.py는 자신이 위치한 디렉토리가 패키지의 일부임을 확인해주는 역할을 한다.
  • python의 버전 3.3부터는 __init__.py 파일이 없어도 패키지를 인식하도록 업데이트되었다고 한다.
  • 하지만 하위 호환을 위해 __init__.py를 생성하는 것이 안전하다.
profile
스스로 배운 것이 오래 간다.

0개의 댓글