모듈

앞에서 함수를 정의해 프로그램 내의 코드를 어떻게 재사용할 수 있는지 확인했습니다. 만약 다른 프로그램에서 여러 함수를 재사용하고 싶다면 어떻게 해야 할까요? 눈치챘을지도 모르겠지만 답은 모듈(module)입니다.

모듈을 만드는 다양한 방법이 있지만 가장 간단한 방법은 함수와 변수가 포함된 확장자가 .py인 파일을 만드는 것입니다.

또 다른 방법은 파이썬 인터프리터 자체를 작성한 네이티브 언어로 모듈을 만드는 것입니다. 예를 들어, C 언어로 모듈을 작성하고 이를 컴파일하면 표준 파이썬 인터프리터를 이용할 때 파이썬 코드에서 사용할 수 있습니다.

모듈은 다른 프로그램에서 해당 모듈의 기능을 활용하기 위해 임포트(import)될 수 있습니다. 이 같은 방법으로 파이썬 표준 라이브러리도 사용할 수 있는 것입니다. 먼저 표준 라이브러리 모듈을 어떻게 사용하는지 보겠습니다.

예제(module_using_sys.py):

import sys

print('The command line arguments are:')
for i in sys.argv:
    print(i)

print('\n\nThe PYTHONPATH is', sys.path, '\n')

출력 결과:

$ python module_using_sys.py we are arguments    # each arg is separated by white space
The command line arguments are:
module_using_sys.py
we
are
arguments


The PYTHONPATH is ['/tmp/py',
# 이곳에 여러 개의 항목이 표시되며, 나머지 항목은 생략합니다
'/Library/Python/2.7/site-packages',
'/usr/local/lib/python2.7/site-packages']

동작 원리

먼저 import 문을 이용해 sys 모듈을 임포트합니다. 기본적으로 이 문장은 파이썬에게 이 모듈을 사용하고 싶다는 뜻으로 번역됩니다. sys 모듈에는 파이썬 인터프리터 및 인터프리터가 실행되는 환경, 즉 시스템(system)과 관련된 기능이 담겨 있습니다.

파이썬이 import sys 문을 실행하면 sys 모듈을 찾습니다. sys 모듈은 파이썬에 내장된 모듈이기 때문에 파이썬은 이 모듈을 어디에서 찾아야 할지 알고 있습니다.

만약 컴파일된 모듈이 아니었다면, 즉 파이썬으로 작성된 모듈이라면 파이썬 인터프리터는 sys.path 변수에 나열된 디렉터리에서 해당 모듈을 찾기 시작합니다. 모듈이 발견되면 해당 모듈의 본문에 포함된 문장이 실행되고 모듈을 사용할 수 있는 상태가 됩니다. 참고로 처음 모듈을 임포트할 때만 초기화(initialization)가 이뤄집니다.

sys 모듈의 argv 변수에 점 표기법(dot notation), 즉 sys.argv를 이용해 접근합니다. 이것은 argv라는 이름이 sys 모듈의 일부라는 사실을 명확하게 보여줍니다. 이 방법의 또 다른 이점은 이 이름이 여러분이 작성한 프로그램 안에서 사용되는 어떠한 argv 변수와도 충돌하지 않는다는 점입니다.

sys.argv 변수는 문자열의 리스트입니다(리스트는 이후 장에서 자세히 설명하겠습니다). 좀 더 구체적으로 말하자면 sys.argv에는 명령줄 인수(command line argument), 즉 명령줄을 이용해 프로그램에 전달한 인수의 리스트가 담겨 있습니다.

만약 IDE를 이용해 프로그램을 실행하고 있다면 메뉴에서 프로그램에 명령줄 인수를 지정하는 방법을 찾아보기 바랍니다.

여기서 python module_using_sys.py we are arguments를 실행하면 python 명령으로 module_using_sys.py 모듈을 실행하게 되고, 그 뒤에 따라오는 것은 프로그램에 전달하는 인수가 됩니다. 파이썬은 명령줄 인수를 프로그램 안에서 쓸 수 있게 sys.argv 변수에 저장합니다.

한 가지 기억할 점은 실행되는 스크립트의 이름은 항상 sys.argv 리스트의 첫 번째 요소라는 점입니다. 따라서 여기서는 'module_using_sys.py'sys.argv[0]이고, 'we'sys.argv[1], 'are'sys.argv[2], 'arguments'sys.argv[3]입니다. 파이썬은 숫자를 1이 아닌 0부터 센다는 데 주의하세요.

sys.path에는 모듈이 어디서 임포트됐는지를 나타내는 디렉터리명의 목록이 담겨 있습니다. sys.path를 보면 sys.path의 첫 번째 문자열은 비어 있는데, 이 빈 문자열은 현재 디렉터리도 PYTHONPATH 환경변수와 동일한 sys.path의 일부라는 점을 나타냅니다. 이것은 현재 디렉터리에 위치한 모듈은 곧바로 임포트할 수 있다는 의미입니다. 그렇지 않다면 sys.path에 나열된 디렉터리 중 하나로 모듈을 옮겨야 할 것입니다.

현재 디렉터리는 프로그램이 실행된 디렉터리라는 것에 주의합니다. 프로그램의 현재 디렉터리를 확인하려면 import os; print(os.getcwd())를 실행합니다.

바이트 컴파일된 .pyc 파일

모듈을 임포트하는 것은 비교적 비용이 드는 일이므로 파이썬은 이를 더 빠르게 하는 몇 가지 기법을 활용합니다. 한 가지 방법은 확장자가 .pyc바이트 컴파일된(byte-compiled) 파일을 만드는 것입니다. 이 파일은 파이썬이 프로그램을 변환했을 때 나오는 중간 형태입니다(들어가며에서 파이썬이 어떻게 동작하는지 설명했던 것을 기억하시나요?). .pyc 파일은 다음번에 다른 프로그램에서 모듈을 임포트할 때 유용합니다. 왜냐하면 모듈을 임포트하는 과정에서 필요한 처리 중 일부를 이미 수행한 상태라서 훨씬 더 빠르기 때문입니다. 게다가 바이트 컴파일된 파일은 플랫폼에 독립적입니다.

참고: .pyc 파일은 보통 .py 파일과 동일한 디렉터리 안에 생성됩니다. 파이썬이 해당 디렉터리에 파일을 쓸 수 있는 권한이 없다면 .pyc 파일은 생성되지 않습니다.

from..import 문

프로그램에 argv 변수를 곧바로 임포트하고 싶다면(매번 sys.를 입력하지 않기 위해) from sys import argv 문을 사용하면 됩니다.

경고: 일반적으로 from..import 문을 사용하는 것은 자제하고 그 대신 import 문을 사용하세요. 이렇게 하면 프로그램이 이름 충돌을 피하고 가독성을 높일 수 있기 때문입니다.

예제:

from math import sqrt
print("Square root of 16 is", sqrt(16))

모듈의 __name__

모든 모듈에는 이름이 있고, 모듈 안의 문장에서는 모듈의 이름을 확인할 수 있습니다. 이는 모듈이 독립적으로 실행되는지, 아니면 다른 프로그램에 임포트되는지를 판단할 때 유용합니다. 앞에서 언급한 바와 같이 모듈은 처음 임포트될 때 모듈에 포함된 코드가 실행됩니다. 이 같은 특성을 이용해 모듈이 그 자체로 사용되느냐 또는 다른 모듈에 임포트되느냐에 따라 서로 다른 방식으로 동작하게 만들 수 있습니다. 이때 모듈의 __name__ 속성을 이용하면 됩니다.

예제(module_using_name.py):

if __name__ == '__main__':
    print('This program is being run by itself')
else:
    print('I am being imported from another module')

출력 결과:

$ python module_using_name.py
This program is being run by itself

$ python
>>> import module_using_name
I am being imported from another module
>>>

동작 원리

모든 파이썬 모듈에는 __name__이 정의돼 있습니다. 이것이 '__main__'이면 모듈이 사용자에 의해 독립적으로 실행되는 것을 의미하고 적절한 동작을 취할 수 있습니다.

모듈 만들기

모듈을 만드는 것은 어렵지 않고 지금껏 해온 일이기도 합니다! 그 이유는 모든 파이썬 프로그램은 모듈이기도 하기 때문입니다. 그저 파일의 확장자를 .py로 지정하기만 하면 됩니다. 다음 예제를 보면 확실히 이해할 수 있습니다.

예제(mymodule.py):

def say_hi():
    print('Hi, this is mymodule speaking.')

__version__ = '0.1'

위 코드는 간단한 모듈 예제입니다. 보다시피 일반적인 파이썬 프로그램에 비해 특별한 부분이 없습니다. 다음으로 이 모듈을 다른 파이썬 프로그램에서 어떻게 사용하는지 보겠습니다.

한 가지 기억해야 할 점은 모듈은 해당 모듈을 임포트하는 프로그램과 같은 디렉터리에 두거나 sys.path에 나열된 디렉터리 중 하나에 둬야 한다는 것입니다.

또 다른 모듈(mymodule_demo.py):

import mymodule

mymodule.say_hi()
print('Version', mymodule.__version__)

출력 결과:

$ python mymodule_demo.py
Hi, this is mymodule speaking.
Version 0.1

동작 원리

여기서도 점 표기법을 사용해 모듈의 요소에 접근한다는 점에 유의합니다. 파이썬은 앞에서 살펴본 점 표기법을 적절히 재활용함으로써 무언가를 하기 위한 새로운 방법을 계속 배울 필요가 없도록 특유의 '파이썬스러움'을 느끼게 해줍니다.

다음은 from..import 구문을 활용한 버전입니다(mymodule_demo2.py).

from mymodule import say_hi, __version__

say_hi()
print('Version', __version__)

mymodule_demo2.py의 출력 결과는 mymodule_demo.py의 출력 결과와 같습니다.

mymodule을 임포트하는 모듈 내에 __version__라는 이름이 이미 선언돼 있었다면 충돌이 발생할 것이라는 데 주의합니다. 이것이 가능한 이유는 __version__라는 이름으로 각 모듈의 버전 번호를 선언하는 것이 일반적이기 때문입니다. 따라서 프로그램의 길이가 조금 더 길어지는 한이 있더라도 항상 import 문을 이용하길 권장합니다.

다음과 같은 구문을 사용할 수도 있습니다.

from mymodule import *

이렇게 하면 say_hi 같은 공개된 이름은 모두 임포트하지만 __version__은 임포트하지 않을 텐데 __version__은 이름이 두 개의 밑줄로 시작하기 때문입니다.

경고: 임포트할 때 별표를 사용하는, 즉 from mymodule import *는 자제해야 합니다.

파이썬의 선(禪)

파이썬의 코딩 원칙 중 하나는 "명시적인 것이 암시적인 것보다 낫다"입니다. 자세한 내용을 보려면 파이썬에서 import this를 실행해 보세요.

dir 함수

파이썬에 내장된 dir() 함수는 객체에 정의된 이름 리스트를 반환합니다. 객체가 모듈이면 이 리스트에는 해당 모듈 안에 정의된 함수, 클래스, 변수가 담겨 있습니다.

이 함수는 인수를 받을 수 있습니다. 인수가 모듈의 이름이면 해당 모듈의 이름 리스트를 반환합니다. 인수를 지정하지 않으면 현재 모듈의 이름 리스트를 반환합니다.

예제:

$ python
>>> import sys

# sys 모듈 안의 속성명을 가져옵니다
>>> dir(sys)
['__displayhook__', '__doc__',
'argv', 'builtin_module_names',
'version', 'version_info']
# 여기서는 몇 개의 항목만 표시합니다

# 현재 모듈의 속성명을 가져옵니다
>>> dir()
['__builtins__', '__doc__',
'__name__', '__package__', 'sys']

# 'a'라는 새 변수를 생성합니다
>>> a = 5

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys', 'a']

# 이름을 삭제/제거합니다
>>> del a

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys']

동작 원리

먼저 임포트한 sys 모듈을 대상으로 dir을 어떻게 사용하는지 봅니다. 이 모듈에 포함된 거대한 속성 리스트를 볼 수 있습니다.

다음으로 dir 함수에 매개변수를 전달하지 않고 사용합니다. 기본적으로 현재 모듈의 속성 리스트를 반환합니다. 임포트한 모듈의 리스트도 이 리스트에 포함된다는 점에 유의합니다.

dir이 실제로 어떻게 동작하는지 관찰하기 위해 a라는 변수를 새로 정의하고 값을 할당한 다음 dir을 확인해 리스트에 같은 이름으로 값이 추가된 것을 확인합니다. del 문을 이용해 현재 모듈의 변수/속성을 제거하고 dir 함수의 출력 결과를 통해 다시 한번 변경 사항이 반영되는 것을 확인합니다.

del 알아두기: del 문은 변수/이름을 삭제하는 데 사용되며, del 문을 실행하고 나면(여기서는 del a) 더는 a 변수에 접근할 수 없습니다. 즉, 전혀 존재하지 않았던 것처럼 처리됩니다.

dir() 함수는 어떠한 객체에도 동작한다는 데 주의합니다. 예를 들어, dir(str)을 실행해 str(문자열) 클래스의 속성을 확인해 보세요.

잠재적으로 속성과 속성값을 반환할 수 있는 vars() 함수도 있지만 이 함수는 모든 경우에 동작하지는 않을 것입니다.

패키지

이제 프로그램을 구성하는 계층구조가 보이기 시작할 것입니다. 대개 변수는 함수 안에 들어갑니다. 함수와 전역 변수는 모듈 안에 들어갑니다. 그럼 모듈을 조직화하고 싶다면 어떻게 해야 할까요? 이때 패키지(package)가 등장합니다.

패키지는 특별한 __init__.py 파일이 포함된, 여러 모듈로 구성된 폴더에 불과합니다. 여기서 __init__.py 파일은 파이썬에게 이 폴더에는 파이썬 모듈이 들어 있어서 특별하다고 알려주는 역할을 합니다.

'asia', 'africa' 등의 하위 패키지가 있고, 이러한 하위 패키지에는 'india', 'madagascar' 등의 모듈이 포함된 'world'라는 패키지를 만들고 싶다고 해봅시다.

다음은 이를 반영한 폴더 구조입니다.

- <sys.path에 존재하는 어떤 폴더>/
    - world/
        - __init__.py
        - asia/
            - __init__.py
            - india/
                - __init__.py
                - foo.py
        - africa/
            - __init__.py
            - madagascar/
                - __init__.py
                - bar.py

패키지는 모듈을 계층적으로 조직화하기 위한 편의 기능에 불과합니다. 패키지의 여러 사례들을 표준 라이브러리에서 보게 될 것입니다.

정리

함수가 프로그램의 재사용 가능한 부품인 것과 같이 모듈은 재사용 가능한 프로그램이라고 할 수 있습니다. 패키지는 모듈을 조직화하는 또 하나의 계층구조입니다. 파이썬에 탑재된 표준 라이브러리는 그러한 패키지와 모듈 들의 예입니다.

지금까지 이러한 모듈을 사용하고 직접 모듈을 만드는 방법을 살펴봤습니다.

다음 장에서는 자료구조라고 하는 흥미로운 개념에 관해 배우겠습니다.