모듈과 패키지

Sawol·2021년 5월 4일
0

I Need Python

목록 보기
6/13
post-thumbnail

모듈

변수, 함수, 클래스 등을 모아 놓은 파일을 스크립트라고 한다. 우리가 cmd 같은 명령 프롬프트에서 python 파일명.py 같은 명령어로 파일을 실행하는 것을 '스크립트를 실행한다' 라고 말한다.
이렇게 하나의 스크립트로 프로젝트를 관리해도 되나, 유지보수를 쉽게 하기위해 여러 파일로 나눌 수 있다. 그리고 이렇게 나뉜 파일에 썼던 함수들을 다시 복사해서 사용하지 않고, 불러올 수 있는 파일을 모듈이라고 한다. 모듈은 다른 모듈을 불러올 수 있고, 모듈 밑에 서브 모듈이 있을 수 있다.

# File name : fibo.py
# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

이를 새로운 파일에 import fibo 를 한다고 해서 새 파일의 심볼 테이블에 값이 들어가진 않는다. 전역 변수 __name__이 실행되면서 오직 모듈 이름만 들어갈 뿐이다.

>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'

이렇게 모듈 이름을 사용해서 함수들에 접근할 수 있다. 만약 함수를 자주 사용할 것이라면 아래처럼 지역 변수로 정의하면 된다.

>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

모듈을 불러오는 다양한 방법

각 모듈은 자신만의 심볼 테이블을 갖고 있는데, 그 모듈에서 정의된 함수들의 전역 심볼 테이블로 사용된다. 그렇기때문에 우리는 모듈을 사용할 때 우리가 작성한 전역 변수와 import한 모듈의 전역변수가 충돌할 걱정을 안해도 된다. 만약, 사용자가 불러온 모듈의 전역 변수에 접근하고 싶으면 modulename.itemname으로 할 수 있다.

from ~ import

모듈에 들어있는 함수를 직접 임포트 하는 방법은 아래와 같다.

>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
>>> fib.fib(500)
NameError: name 'fibo' is not defined

import fibo를 하지 않았기때문에 심볼 테이블에는 fibo가 아닌 fibfib2만 존재한다. 그래서 fibo를 이용해 fib을 불러오면 error가 발생한다.
모듈에 정의된 모든 함수를 import 하는 방법도 있다.

>>> from fibo import *
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

함수 명이 밑줄_로 시작되는 것을 제외한 모든 함수를 불러온다. 다만, 이러한 방법은 권장하지 않는데, 그 이유는 모듈의 함수명과 사용자의 변수명이 충돌 할 수 있기 때문이다. 그리고 또한, 가독성도 덜어지니 되도록 *은 사용하지 말자.

as

as는 길이가 긴 모듈 또는 함수명의 별칭을 지어주는 것이다. 만약, 모듈 또는 함수명의 길이가 엄청 길 경우 가독성도 떨어지고 코드를 작성하는 것에도 어려움이 클 것이다. 그래서 as를 사용해서 별칭을 만든다.

# 모듈에 as를 사용한 경우
>>> import fibo as fib	
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
# 함수에 as를 사용한 경우
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

모듈을 스크립트로 사용하기

python fibo.py 으로 실행을 하면 __name____main__으로 설정 된다.

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

그래서 모듈 끝에 위 코드를 붙이면 모듈뿐만 아니라 스크립트로도 작동된다. 오직 모듈이 main일 경우에만 동작되므로 import하여 모듈을 사용될 때는 위 코드가 동작하지 않는다.

$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34

보통 모듈에 대한 사용자 인터페이스를 제공하거나 테스트 목적으로 사용된다.

모듈 검색 경로

파이썬에서 모듈을 불러오기 위해 해당 파일을 찾을 때 검색 순서는 아래와 같다.

  1. python 내장 모듈에서 검색
  2. sys.path에 담긴 디렉터리들에서 검색

그렇기 때문에 만약 python 내장 모듈과 같은 이름의 모듈을 생성해도 내장 모듈이 우선시되어 import된다.
sys.path에 담기는 디렉터리의 순서는 아래와 같다.

  1. 현재 실행 중인 python 코드를 포함하는 폴더
  2. 환경 변수에 정의된 모듈 검색 경로
import sys
print(sys.path)
['현재 실행 중인 python 코드를 포함하는 폴더`, `환경 변수에 정의된 경로`]
sys.path.append('C:\\')
print(sys.path)
['현재 실행 중인 python 코드를 포함하는 폴더`, `환경 변수에 정의된 경로`, 'C:\\']

그래서 위처럼 sys.path에 경로를 추가할 수도 있다.

패키지

앞서 봤던 모듈의 집합을 의미한다. 즉, 패키지는 기능들이 모듈 여러개로 나누어져 있다. 패키지 이름의 폴더 안에 여러개의 모듈(.py)이 모여있는 구조이다. 패키지 또한 import할 때 모듈과 마찬가지로 sys.path에 있는 디렉터리들을 검색하면서 패키지를 찾는다. 파이썬이 일반 폴더와 패키지 폴더를 구분하기 위해 패키지 폴더에는 __init__.py라는 파일이 필요하다. 이 파일이 있으면 파이썬은 해당 폴더가 패키지 폴더임을 인식한다. __init__.py 파일은 빈 파일이여도 상관없으며 초기화 코드를 실행할 수도 있다.
아래는 sound 패키지의 예이다.

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

패키지를 불러오는 다양한 방법

import 와 from ~ import

#import item.subitem.subsubitem
import sound.effects.echo
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)


#from package import item

from sound.effects import echo
echo.echofilter(input, output, delay=0.7, atten=4)

from sound.effects.echo import echofilter
echofilter(input, output, delay=0.7, atten=4)

sound 패키지 아래에 있는 effects 모듈 아래의 echo 모듈을 불러오는 코드이다. import는 먼저 item이 패키지에 정의 되어 있는지 검사하고, 없으면 모듈이라고 가정하고 다시 찾는다. 이때도 찾지 못하면 importError를 출력한다.
import item.subitem.subsubitem은 마지막을 제외하곤 항상 패키지와 모듈이여야한다. 마지막은 모듈 또는 클래스나 함수, 변수 등이 될 수 있다.

패키지에서 * 사용하기

from sound.effects import * 을 사용하면 effects 아래의 모듈이 다 불러오지 않고 import sound.effects를 사용한 것처럼 sound.effects만 불러온다. 그래서 개발자가 직접 *을 사용시 불러올 모듈을 정의할 수 있다.

# sound/effects/__init__.py
__all__ = ["echo", "surround", "reverse"]

sound/effects/__init__.py에 위 코드를 담으면 from sound.effects import *을 사용하면 세 모듈만 import된다.

패키지에서 내부 모듈끼리 불러오기

이웃 패키지의 서브 모듈을 import할 수 있는 방법은 크게 절대 경로와 상대 경로 두 가지가 있다.

절대경로

sound.filters.vocoder 모듈이 sound.effects 패키지의 echo모듈이 필요하다면, from sound.effects import echo 처럼 절대 경로를 사용하면 된다.

상대경로

부모 패키지를 가리키기 위해 앞에 .이 붙는다.

from . import echo
from .. import formats
from ..filters import equalizer

상대경로 import의 경우 현재 모듈의 이름에 기반을 두기 때문에,(메인 모듈의 이름은 항상 __main__임) 메인 모듈로 사용될 목적의 모듈들은 반드시 절대경로 import를 사용해야한다. 그러니까 그냥 절대경로만 사용하자!

0개의 댓글