[Python 기초] 파이썬 프로그래밍의 핵심 - 패키지(Package)

업데이트:

개요

jpg

패키지란?

지금까지 모듈(module), 클래스(class), 함수(function), 변수(variables)등을 알아보았다.
쉽게 생각해보면 지금 얘기한 순으로 포함되는 상위 개념이라는 것도 언급했었다.

패키지(package)란 도트(.)를 이용하여 파이썬 모듈을 계층적(디렉터리 구조)으로 관리할 수 있게 해준다. 즉, A.B인 경우 A는 패키지, B는 모듈이 된다.


1. 패키지의 구조

파이썬 패키지는 디렉터리와 파이썬 모듈로 이루어지며 구조는 다음과 같다.

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패키지의 예시이다.
여기서 game은 이 패키지의 루트 디렉터리이고 sound, grahpic, play는 서브 디렉터리이다.
쉽게 말해 상위폴더 하위폴더로 생각할 수 있다.


2. 패키지 만들기

위의 가상의 game패키지를 만들고 __init__.py파일은 비워두고 다른 파일은 다음과 같이 만든다.

# echo.py
def echo_test():
	print("echo")
# render.py
def render_test():
	print("render")
# echo.py
def echo_test():
	print("echo)

그리고 앞서 배웠던 sys모듈을 이용해서 패키지를 불러올 수 있도록 디렉터리를 설정한다.

import sys
sys.path.append("D:\Python")


3. 패키지 안의 함수 실행하기

패키지 안의 함수를 사용하기 위해 불러오는 방법은 3가지가 있다.
3가지 예제를 실행해볼때, 1가지가 끝나면 인터프리터를 종료하고 다시 해야한다. 왜냐하면 이전에 import했던 기록이 남아 결과가 정확하지 않을 수 있기 때문이다.

앞의 모듈(module)포스팅을 참고하자.

3-1. 모듈을 import해서 실행하기

import game.sound.echo
game.sound.echo.echo_test()
[Output] echo

모듈까지 불러왔기 때문에 함수를 실행하려면 모듈.모듈함수의 형태가 되어야한다.

3-2. 모듈이 있는 디렉터리까지를 from .. import하여 실행하기

from game.sound import echo
echo.echo_test()
[Output] echo

from까지의 디렉터리는 함수를 실행할때 입력해줄 필요가 없다.

3-3. 모듈까지 fromm...import하여 함수자체를 실행하기

from game.sound.echo import echo_test
echo_test()
[Output] echo

3-4. 불가능한 경우 1

하지만 다음과 같이 함수를 사용하는 것은 불가능하다.

import game
game.sound.echo.echo_test()  #이건 불가능하다
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-3-d7578ae96834> in <module>()
      1 import game
----> 2 game.sound.echo.echo_test()


AttributeError: module 'game' has no attribute 'sound'

import game으로 불러오면 game폴더 자체 디렉터리의 모듈 또는 __init__.py에 정의된 것만 참조할 수 있다.

3-5. 불가능한 경우 2

import game.sound.echo.echo_test
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

<ipython-input-4-7d269958f27d> in <module>()
----> 1 import game.sound.echo.echo_test


ModuleNotFoundError: No module named 'game.sound.echo.echo_test'; 'game.sound.echo' is not a package

import a.b.c 처럼 도트연산자를 이용할 때, 마지막 항목인 c는 함수가 아니라 모듈 or 패키지로 끝나야 한다.

즉, 패키지를 이용해 함수를 불러올때의 주의할 사항은 다음과 같다.

최소한 해당 모듈이 있는 디렉터리까지는 from이나 import로 접근해야한다.
import의 최대 범위는 모듈로 끝나야한다. 모듈 내의 함수까지는 불가능하다.


4. __all__의 용도

다음을 따라해 보자.

from game.sound import *
echo.echo_test()
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-2-b76d5b24d74b> in <module>()
      1 from game.sound import *
----> 2 echo.echo_test()


NameError: name 'echo' is not defined

앞의 모듈 포스팅에서 배웠던, *를 이용해 모듈 내 모든 함수를 불러오려고 했지만 오류가 발생했다.

그 이유는 __all__이라는 변수를 설정해주지 않았기 때문에 *가 동작하지 않은 이유이다.

특정 디렉터리의 모듈을 *을 이용해 import할 때에는 다음과 같이 해당 디렉터리의 __init__.py파일에 __all__이라는 변수를 설정하고 import할 수 있는 모듈을 정의해 주어야 한다.

# sound 디렉터리의 __init__.py 파일
__all__ = ['echo']

여기서 __all__의 의미는,
sound 디렉터리에서 *기호를 이용하여 import할 경우 이곳에 정의된 echo모듈만 import된다는 것이다.

from game.sound import *
echo.echo_test()
[Output] echo

그 결과 정상적으로 실행되는 것을 볼 수 있다.


5. relative 패키지

relative 패키지란 말그대로 ‘관련된’이라는 의미이다.

만약 graphic 디렉터리의 render.py모듈이 sound 디렉터리의 echo.py모듈을 사용하고 싶다면, 다음과 같이 render.py를 수정하면 가능하다.

# render.py
from game.sound.echo import echo_test()
def render_test():
    print("render")
    echo_test()

그 후 render.py모듈을 이용해 다음과 같이 실행해보자.

from game.graphic.render import render_test
render_test()
[Output]
render
echo

즉, render.py모듈 내에서 echo 모듈을 import하여 위와 같이 ‘relative’하게 사용하는 것도 가능하다.


Reference

도서 [점프 투 파이썬] 를 공부하며 작성하였습니다.

댓글남기기