10.2.1 모듈을 구조적으로 관리하기

영어 단어 ‘package’는 꾸러미, 묶음을 뜻한다. 파이썬의 패키지는 여러 개의 모듈·패키지를 묶은 것이다. 모듈을 왜 묶어야 할까? 모듈 하나가 너무 방대해지면, 모듈을 더 세분화해 여러 개의 모듈로 나누고 싶을 것이다. 예를 들어, 게임 프로그램을 구성하는 세 모듈 ‘화면 출력’, ‘입력 처리’, ‘데이터 모델’은 다음과 같이 더욱 세분화할 수 있다.

  • 화면 출력
    • 좌표와 도형 계산
    • 사용자 인터페이스 그리기
    • 배경 그리기
    • 캐릭터 그리기
  • 사용자 입력 처리
    • 키보드 입력 처리
    • 포인트 입력 처리
      • 마우스 입력
      • 터치 입력
  • 데이터 모델
    • 캐릭터 정보
      • 인간형 캐릭터
      • 동물형 캐릭터
      • 로봇형 캐릭터
    • 사물 정보
      • 휴대용품 정보
      • 배치용 사물 정보

이제 본래 모듈이었던 ‘화면 출력’, ‘입력 처리’, ‘데이터 모델’은 더 작은 모듈들을 묶은 패키지가 된다. 또한, ‘포인트 입력 처리’, ‘캐릭터 정보’, ‘사물 정보’처럼 다른 패키지에 속하는 동시에 세부 모듈을 묶기도 하는 패키지도 있다. 이처럼, 패키지를 사용해 모듈을 구조적으로 관리할 수 있다.

10.2.2 패키지 만들기

모듈을 만들 때는 파이썬 소스 코드 파일을 만들면 된다. 그렇다면 모듈을 묶는 패키지는 무엇으로 만들까? 모듈을 묶는다는 것은 곧 파일을 묶는 것을 의미한다. 따라서 파일을 묶는 것이 패키지다. 그렇다. 패키지는 파이썬 파일을 모아 놓은 디렉터리다.

패키지 구성하기

연습 삼아, 여러가지 모듈을 모은 패키지를 만들어 보자. 패키지를 만들어 볼 위치는 이 장의 파이썬 실습 디렉터리 chapter_10이다. 이 경로 아래에 다음과 같은 구조의 디렉터리와 파일을 만들자.

그림 10-3 게임 프로그램 패키지 구성하기

그림 10-5 게임 프로그램 패키지 구성하기

실습 경로에 model 디렉터리와 graphic 디렉터리를 만들고, 다시 model 디렉터리 아래에는 character 디렉터리를 만들어 두면 된다. 패키지를 구성하는 파이썬 모듈 파일들은 아래와 같이 작성해 두자.

코드 10-9 패키지를 구성하는 각 모듈의 내용

--- model/__init__.py 파일 ---
from . import character


--- model/character/__init__.py 파일 ---
from . import human
from . import robot


--- graphic/__init__.py 파일 ---
from . import background
from . import character


--- graphic/background.py 파일 ---
def draw():
    print('화면에 배경을 출력합니다.')


--- graphic/character.py 파일 ---
def draw():
    print('화면에 캐릭터를 출력합니다.')


--- model/character/human.py 파일 ---
cheoli = {'name': '철이', 'dialog': '또 하나의 별이 사라졌어'}


--- model/character/robot.py 파일 ---
maetel = {'name': '메텔', 'dialog': '나는 청춘의 환영'}

각 디렉터리에 만든 __init__.py 파일이 생소할 텐데, 아래에서 설명하니 일단 따라 입력하면 된다. 패키지와 모듈을 모두 구성했으면 대화식 셸에서 임포트하여 확인해 보자.

코드 10-10 패키지를 구성하는 각 모듈의 내용

>>> import model                  # model 패키지 임포트
>>> model.character.human.cheoli  # model 패키지의 하위 항목 사용
{'name': '철이', 'dialog': '또 하나의 별이 사라졌어'}

>>> import graphic                # graphic 패키지 임포트
>>> graphic.background.draw()     # graphic 패키지의 하위 항목 사용
화면에 배경을 출력합니다.

위 코드에서 볼 수 있듯이, 패키지의 모듈은 모듈 내에 정의된 이름을 가리킬 때처럼 패키지.모듈 표현으로 가리킬 수 있다. 패키지에 정의된 특정 모듈만을 임포트하고 싶다면 from 패키지 import 모듈 과 같이 from 예약어를 이용해 임포트할 수도 있다.

코드 10-11 패키지의 일부 구성요소만 임포트하기

>>> from graphic import character
>>> character.draw()
화면에 캐릭터를 출력합니다.

>>> from model.character.robot import maetel
>>> maetel['dialog']
'나는 청춘의 환영'

__init__.py 파일

각 패키지 디렉터리에 하나씩 만들어 둔 __init__.py 파일은 무엇일까? 이 파일은 파이썬이 디렉터리를 패키지로 인식하도록 하는 파일이다. 파이썬의 모든 패키지 디렉터리는 __init__.py 파일을 갖고 있어야 한다. 이 파일이 없으면 디렉터리가 패키지로 인식되지 않는다.

이름에서도 짐작할 수 있듯, 이 파일은 패키지를 임포트할 때 초기화하기 위한 파일이기도 하다. 패키지의 초기화에 필요한 코드라면 무엇이든 담을 수 있다. 주로 하위 패키지·모듈을 임포트하는 명령이 포함된다.

예를 들어, 앞에서 만든 model 패키지의 __init__.py 파일에는 from . import character라는 코드가 포함되었는데, 이는 __init__.py 파일이 있는 위치(패키지의 위치)에서 character 패키지를 임포트하도록 한다. 이 덕분에 model 패키지만 임포트하고도 그 하위 패키지인 model.character 패키지를 가리킬 수 있다.

10.2.3 패키지와 모듈의 경로

파이썬 안에서 패키지와 모듈의 경로는 패키지.모듈과 같은 형식으로 점 기호(.)를 이용해 계층적으로 나타낼 수 있다. 패키지는 디렉터리이고 모듈은 파일이므로, 이는 운영 체제에서 파일 경로를 나타내는 형식을 닮았다.

  • 파이썬 형식 모듈 경로: model.character.human
  • 윈도우 형식 파일 경로: model\character\human.py
  • 유닉스 형식 파일 경로: model/character/human.py

파이썬에서는 모듈 이름에 확장자를 붙이지 않는다는 것과 디렉터리를 구별하는 기호가 다르다는 점을 빼면 디렉터리의 계층을 나타내는 방식이 동일하다.

모듈 경로 표기를 읽을 때 모호한 점

파이썬에서 모듈 경로 표기를 읽을 때, 가리키는 대상이 패키지인지, 모듈인지, 변수인지를 경로 표기만으로는 알 수 없어 주의가 필요하다. 예를 들어 a.b.c라는 경로에서 cb 패키지의 하위 패키지·모듈이거나, b 모듈에 정의된 객체의 이름(변수)일 수도 있다.

파이썬에만 이런 문제가 있는 건 아니다. 운영 체제의 파일 경로도 마찬가지다. a/b/c라는 경로에서 ab는 확실히 디렉터리이지만, c는 파일인지 디렉터리인지 모른다.

절대 경로와 상대 경로

어떤 대상의 위치를 가장 상위 항목에서부터 모두 표기한 것을 ‘절대 경로’라고 하고, 임시 위치를 기준으로 표기한 것을 ‘상대 경로’라고 한다. 다음 표는 운영 체제와 파이썬의 경우로 나누어, 절대 경로와 상대 경로의 예를 들어 본 것이다.

형식 절대 경로 상대 경로
파이썬의 모듈 model.character.human character.human
윈도우의 파일 A:\model\character\human character\human
유닉스의 파일 /model/character/human character/human

표 10-1 절대 경로와 상대 경로의 예

상대 경로는 특정 위치(예: 현재 작업 디렉터리)를 기준으로 경로를 나타내는 방식이므로, 기준이 어디냐에 따라 같은 대상이라도 표현하는 방식이 달라진다. 절대 경로도 기준이 어떤 한 지점으로 정해진 상대경로라고 할 수 있다.

어떤 경로가 상대 경로임을 강조하기 위해 ./character/human과 같이 경로 앞에 점 기호(.)를 붙이기도 한다. 이 때 점 기호는 ‘현재 경로’를 의미한다.

파이썬에서는 import 문에서 점 기호를 이용해 모듈을 상대 경로로 임포트할 수 있다. 코드 10-9에서 만든 model 패키지의 __init__.py 파일에 작성한 from . import character 문은 현재 패키지(model 패키지)를 기준으로 상대 경로로 character 패키지를 임포트하라는 뜻이다.