21. (부록) 모듈 고급 활용법#

하나의 모듈이 독립적으로 제공되기도 하지만 다른 모듈과 함께 하나의 모음집으로 제공되기도 한다. 모음집의 크기와 용도에 따라 패키지, 라이브러리, 프레임워크 등 다양한 이름으로 불린다.

21.1. 모듈, 패키지, 라이브러리, 프레임워크#

패키지

패키지package는 모듈을 모아놓은 디렉토리(폴더)이며, __init__.py 모듈을 포함한다. 패키지 안에 하위 패키지가 포함될 수 있으며, 각 하위 패키지 모두 __init__,py 모듈을 포함한다. __init__.py 모듈은 해당 패키지가 사용될 때 필요한 기본 설정이 저장되어 있고 자동 실행된다. 아래 그림이 전형적인 패키지 구조를 보여준다.

아래 그림은 패키지와 단순히 모듈을 포함하는 디렉토리(폴더)의 차이점을 잘 보여준다.

라이브러리

라이브러리library는 모듈, 패키지 등 재사용이 가능한 코드의 모음집을 통칭헤서 부르는 이름이다. 패키지가 하위 패키지를 포함하기에 라이브러리로 불리기도 하지만 라이브러리는 여러 개의 패키지로 이루어진 모음집으로 하나의 패키지와 구분된다. 파이썬 표준 라이브러리에서 기본으로 제공되는 패키지와 모듈을 확인할 수 있다.


또한 게임 프로그래밍에 사용되는 Pygame, 데이터 분석에 필수인 Numpy와 Pandas, 웹에서 필요한 데이터 수집에 유용한 BeautifulSoup, 머신러닝/딥러닝 분야의 Tensorflow, Keras, PyTorch 등이 대표적인 제3자 파이썬 라이브러리다. 제3자 라이브러린란 파이썬 공식 홈페이지가 아닌 다른 방식으로 제공되는 라이브러리를 가리킨다.

프레임워크

프레임워크framework는 라이브러리 보다 포괄적인 개념이다. 라이브러리가 도구 모음집만 제공하는 반면에 프레임워크는 라이브러리와 함께 라이브러리를 쉽게 적용할 수 있는 틀frame과 아키텍처architecture를 함께 제공한다.

예를 들어, 플라스크Flask 프레임워크는 웹서버 개발에 적절한 틀과 구조를, 장고Django 프레임워크는 웹 어플리케이션 구현에 최적인 틀과 구조를 제공한다. 사용자는 프레임워크가 제공하는 틀과 구조에 맞춰 적절한 코드를 작성하면 원하는 결과를 쉽고 빠르게 구현할 수 있다.

21.2. pip 파이썬 패키지 관리자#

파이썬 프로그래밍에 사용되는 모든 모듈, 패키지, 라이브러리, 프레임워크 등은 일반적으로 pip 이라는 파이썬 패키지 관리자를 이용하여 설치하고 관리한다. 예를 들어 넘파이 모듈을 설치하려면 다음 명령을 실행한다. 달러 기호($) 터미널의 프롬프트를 가리키며 실제로 입력하지는 않음에 주의하라.

$ pip install numpy

주피터 노트북에서도 동일한 방식으로 설치할 수 있다. 단, 아래 처럼 느낌표로 시작해야 한다.

>>> !pip install numpy

모듈, 패키지, 라이브러리, 프레임워크 중에서 가장 작은 단위인 모듈만 불러와서import 모듈에 포함된 함수, 클래스 등을 사용할 수 있다. 모듈을 불러오는 기본 방식은 다음과 같다.

>>> import 모듈명

반면에 모듈이 아닌 패키지를 불러올 수도 있지만 그러려면 패키지 폴더에 있는 __init__.py 모듈에 해당 패키지를 불러올 때 기본적으로 함께 불러오는 모듈이 지정되어 있어야 한다. 예를 들어 numpy 는 패키지이지만 아래 방식으로 불러올 수 있다.

>>> import numpy

그러면 __init__().py 모듈에 지정된 방식으로 필요한 다른 모듈과 패키지가 함께 불려오게 된다. 보다 자세한 사항은 코딩도장: 패키지에서 from import 응용하기를 참고한다.

모듈은 크게 세 종류로 나뉜다.

  • 내장 모듈: math, urllib.request, random, turtle, os, sys 등 파이썬을 설치할 때 기본으로 제공되는 모듈

  • 제3자 라이브러리third-party library 모듈: numpy.random, matplotlib.pyplot, pygame.mixer 등 제3자가 제공한 라이브러리에 포함된 모듈

  • 사용자 정의 모듈: 개인 프로젝트를 위해 직접 작성한 파이썬 코드 파일

21.3. 사용자 정의 모듈#

파이썬 파일 저장

아래 코드를 담고 있는 wc.py 파일을 모듈로 불러와서 활용해보자.

def linecount(filename):
    count = 0
    with open(filename) as f:
        for line in f:
            count += 1
    return count

wc.py 파일을 직접 생성하거나 아래 myWget파일을 이용하여 다운로드한다.

from urllib.request import urlretrieve
from pathlib import Path

# 서버 기본 주소
base_url = "https://raw.githubusercontent.com/codingalzi/pybook/master/jupyter-book/codes/"
# 파일 저장 위치
code_path = Path() / "codes"

def myWget(filename):
    file_url = base_url + filename
    code_path.mkdir(parents=True, exist_ok=True)
    target_path = code_path / filename

    return urlretrieve(file_url, target_path)

아래 코드를 실행하면 현재 디렉토리에 codes 라는 하위 디렉토리가 생성되고 그 안에 wc.py 파일이 저장된다.

myWget('wc.py')
(PosixPath('codes/wc.py'), <http.client.HTTPMessage at 0x7f625ef91110>)

다운로드된 파일의 내용을 확인하면 다음과 같이 앞서 언급한 내용과 동일하다.

with open(code_path / "wc.py") as f:
    print(f.read())
def linecount(file_name):
    count = 0
    with open(file_name) as f:
        for line in f:
            count += 1
    return count

사용자 정의 모듈 불러오기

만약에 wc.py 파일이 codes 폴더가 아닌 현재 작업 디렉토리에 저장되어 있다면 단순히 아래 방식을 사용하면 된다.

>>> import wc

하지만 여기서는 그렇지 않기에 좀 더 복잡하다. 이유는 앞서 패키지를 설명했던 것처럼 codes 디렉토리를 패키지로 지정한 다음에 파이썬 실행기interpreter에 해당 패키지의 존재를 알려야 하기 때문이다.

21.4. 패키지 지정#

특정 폴더를 파이썬 패키지로 지정하려면 해당 폴더에 __init__.py 파일명을 가진 파일이 존재하면 된다. __init__.py 파일은 해당 패키지를 불러올 때 사용할 설정을 담은 모듈인데 아무 설정도 하지 않는다면 비어두어도 된다. 여기서는 아무 설정도 하지 않는 빈 파일로 사용한다.

비어 있는 __init__.py 파일을 생성해서 codes 디렉토리에 저장하거나 아래 명령문을 실행해서 해당 파일을 다운로드 한다.

myWget('__init__.py')
(PosixPath('codes/__init__.py'), <http.client.HTTPMessage at 0x7f625efa6190>)

os 모듈의 listdir() 함수를 이용하여 codes 디렉토리에 두 개의 파일이 포함되어 있음을 확인한다.

import os

os.listdir(code_path)
['collision_detection',
 'collision_detection.zip',
 'lc.py',
 'wc.py',
 '__init__.py',
 '__pycache__']

__pycache__ 디렉토리

파이썬 실행기interpreter가 실행에 필요한 파일들을 생성해서 보관한다.

21.5. 라이브러리 경로#

현재 작업 디렉토리가 아닌 디렉토리에 포함된 파이썬 파일을 모듈로 불러오는 기본적인 방법은 라이브러리 경로library path에 해당 디렉토리를 임시로 추가하는 것이다.

영구적 라이브러리 경로 추가

특정 디렉토리를 라이브러리 경로에 영구적으로 추가하는 방법은 여기서는 다루지 않는다. 필요하다면 파이썬 경로 추가 방법를 참고할 수 있다.

파이썬이 기본적으로 지원하는 라이브러리들의 경로들의 리스트를 sys.path 변수가 가리킨다.

import sys

sys.path
['/mnt/c/Users/gslee/Documents/GitHub/pybook/jupyter-book',
 '/home/gslee/miniconda3/lib/python311.zip',
 '/home/gslee/miniconda3/lib/python3.11',
 '/home/gslee/miniconda3/lib/python3.11/lib-dynload',
 '',
 '/home/gslee/miniconda3/lib/python3.11/site-packages']

따라서 sys.path 가 가리키는 리스트에 원하는 디렉토리의 경로를 추가만 하면 된다. Path 객체의 absolute() 메서드가 지정된 경로의 절대경로를 반환한다.

code_path.absolute()
PosixPath('/mnt/c/Users/gslee/Documents/GitHub/pybook/jupyter-book/codes')

위 경로를 문자열로 변환한 다음에 라이브러리 경로에 추가하지.

sys.path.append(str(code_path.absolute()))

이제 새로운 경로가 추가된 것을 확인할 수 있다.

sys.path
['/mnt/c/Users/gslee/Documents/GitHub/pybook/jupyter-book',
 '/home/gslee/miniconda3/lib/python311.zip',
 '/home/gslee/miniconda3/lib/python3.11',
 '/home/gslee/miniconda3/lib/python3.11/lib-dynload',
 '',
 '/home/gslee/miniconda3/lib/python3.11/site-packages',
 '/mnt/c/Users/gslee/Documents/GitHub/pybook/jupyter-book/codes']

라이브러리 경로에 포함된 디렉토리의 파이썬 파일은 바로 불러올 수 있다.

import wc

이제 linecount() 함수를 사용하면 된다. 아래 코드는 wc.py 파일이 총 6개의 줄을 담고 있음을 확인해준다.

wc.linecount(code_path / "wc.py")
6

21.6. 모듈 파일 실행#

모듈엔 자주 사용될 수 있는 함수, 클래스, 상수 등을 저장한다. 그런데 모듈을 불러올 때 모듈 파일에 포함된 모든 명령문이 실행된다. 따라서 불필요한 코드를 모듈에 포함시키는 일은 삼가한다.

반면에 파이썬 파일을 모듈로써의 기능과 함께 하나의 완성된 프로그램으로 작동하게 할 수도 있는데 그럴 때는 보통 실행하고자 하는 코드를 파일의 맨 아래에 아래 형식으로 추가한다.

if __name__ == '__main__':
    명령문

__name__ 은 모듈의 이름을 가리키는 파일 객체의 속성 변수이며, __main__ 은 현재 코드를 실행하는 주체를 가리키는 값이다. 그러면 이와 같이 작성된 코드의 실행여부는 위 코드를 포함한 파일이 사용되는 방식에 따라 결정된다.

모듈로 사용되는 경우

만약 파일을 직접실행하지 않고 다른 파일의 코드에서 모듈로 불러오면 __name__ == '__main__'는 거짓이 되어 if 문의 본체 명령문이 무시된다. 이유는 __name__은 모듈의 이름을, __main__은 해당 모듈을 불러온 다른 파일을 가리키기에 서로 다른 값을 가리키기 때문이다.

파일을 직접 실행하는 경우

예를 들어 아래와 같이 터미널에서 해당 파일을 실행하면 지정된 명령문이 실행된다. 이유는 __name____main__ 모두 해당 모듈 파일을 가리키기 때문이다.

$ python 파일명.py

파일 실행에 인자가 필요한 경우

경우에 따라 아래와 같은 방식으로 파이썬 파일을 실행할 때 실행되는 코드에서 요구되는 인자를 지정해야 할 필요도 있다.

$ python 파일명.py 인자1 인자2 ... 인자n

예를 들어 test.py 라는 파이썬 파이썬 파일에 다음과 같은 코드가 포함되어 있다고 가정한다.

import sys
print("파일 실행 인자:", sys.argv)

그리고 아래와 같이 터미널에서 아래와 같이 명령문을 실행해 보자.

$ python test.py arg1 arg2 arg3

그러면 다음 문장이 터미널 화면에 출력된다.

파일명과 실행 인자: ['test.py', 'arg1', 'arg2', 'arg3']

즉, python 명령어의 인자로 사용되는 test.py, arg1, arg2, arg3 모두 문자열로 갖는 리스트가 파일 내부에서 sys.argv 변수에 할당된다. 예를 들어 test.py 파일에 아래 코드가 저장되어 있다고 가정하자.

import sys

int1 = int(sys.argv[1])
int2 = int(sys.argv[2])

print(f"{int1}{int2}의 곱: {int1*int2}")

터미널에서 위 파일을 2와 7 두 인자와 함께 실행하면 아래와 같이 실행된다.

$ python test.py 2 7
2와 7의 곱: 14