패키지
패키지는 도트(_)를 사용하여 파이썬의 모듈들을 계층적 구조로 관리하는 것으로 모듈간의 계층적 관계를 통해 유지와 보수를 쉽게 만들어 준다. 예로 Person_jam.py 라면 Person은 패키지 이름이고 jam은 모듈로 Person 패키지의 jam모듈로 해석된다.
가상의 game 패키지 예시
game/ __init__.py sound/ __init__.py echo.py wav.py graphic/ __init__.py screen.py render.py play/ __init__.py run.py test.py |
game, sound, graphic, play는 디렉터리고 확장가 .py인 파일은 파이썬의 모듈이다. game인 이 디렉터리 사이에서 루트 디렉터리이며 그 외는 서브 디렉터리이다.
큰 파이썬 프로그램에서는 이러한 패키지 구조의 프로그램 설계가 공동 작업이나 유지 보수 등 여러 면에서 유리하다. 또한 패키지 구조로 각 디렉터리에 모듈이 저장되므로 다른 모듈과 이름이 겹치더라도 디렉터리가 동일하지않다면 사용가능하다.
패키지 생성
이제 위 예와 비슷한 game 패키지를 직접 만들어 보며 패키지에 대해서 알아보자.
실습은 반드시 명령 프롬프트에서 파이썬 인터프리터를 실행하여 진행해야 한다.
패키지 기본 구성 요소 준비하기
1. C:/doit 디렉터리 밑에 game 및 기타 서브 디렉터리를 생성하고 .py 파일들을 만든다
2. 각 디렉터리에 __init__.py 파일을 만들어 놓기만 하고 내용은 일단 비워 둔다.
3. echo.py 파일은 다음과 같이 만든다.
def echo_test(): print("echo")
4. render.py 파일은 다음과 같이 만든다.
def render_test(): print("render")
5. 다음 예제를 수행하기 전에 우리가 만든 game 패키지를 참조할 수 있도록 명령 프롬프트 창에서 set 명령어로 PYTHONPATH 환경 변수에 C:/doit 디렉터리를 추가한다. 그리고 파이썬 인터프리터(Interactive shell)를 실행한다.
set PYTHONPATH = C:/doit
여기까지 위의 예시에서와 같이 패키지 상태를 초기화한 뒤에 환경변수에 디렉터리를 등록해서 바로 사용할 수 있도록 환경을 설정해 두었다.
패키지 안의 함수 실행
패키지를 사용하여 함수를 실행시키는 방법은 3가지가 존재한다.
1. echo 모듈을 import 하여서 사용하기
>>> import game.sound.echo
>>> game.sound.echo.echo_test()
echo
2. echo 모듈이 있는 디렉터리까지 from .. import 하여 사용하기
>>> from game.sound import echo
>>> echo.echo_test()
echo
3. echo 모듈 내에 존재하는 echo_tesh 함수 자체를 직접 import 하여 실행하기
>>> from game.sound.echo import echo_test
>>> echo_test()
echo
이 때, 루트 디렉터리를 import 하여 서브 디렉터리 내에 모듈의 함수는 실행이 불가능하다.
>>> import game
>>> game.sound.echo.echo_test() => ( X )
import game 을 수행한뒤에는 game 디렉터리 내에 __init__.py에 정의한 것만 참조가 가능하다.
또한 모듈내에 함수를 직접 import 하는 것도 불가능하다. import에 가장 마지막 항목은 모듈 또는 패키지이어야 한다.
>>> import game.sound.echo.echo_test() => ( X )
__init__.py
__init__.py 파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할을 한다. 만약 우리가 선언한 game, sound 등에 __init__.py 파일이 없다면 패키지로 인식이 되지 않는다.
( 파이썬 3.3부터는 __init__.py를 생략해도 패키지로 인식하지만 하위 버전 호환을 위해 생성하는 것이 바람직하다.)
__init__.py 파일 내에 __all__ 변수를 설정할 수 있는데 이는 특정 디렉터리를 import할 때 from절에 마지막 항목이 모듈인 경우 해당하는 패키지에서 *를 어떻게 처리할지 설정한다.
relative 패키지
graphic 디렉터리에 render.py 모듈이 sound 디렉터리의 echo 모듈을 사용하고 싶다면 remder.py에서 from .. import로 사용이 가능하다.
from game.sound.echo import echo_test # sound 디렉터리의 echo 모듈을 추가했다
def render_test():
print("render")
echo_test()
>>> from game.graphic.render import render_test
>>> render_test()
render
echo
하지만 같은 패키지 내의 경우에는 다음과 같이 relativ한 import 설정도 가능하다.
여기에서 ..은 render.py 파일의 부모 디렉터리를 의미한다. render.py 파일의 부모 디렉터리는 game이므로 같은 디렉터리를 계승받는다 그로 인해서 위와 같은 import가 가능하다. ( render.py 파일의 현재 디렉터리는 graphic이고 부모 디렉터리는 game이다. )