모듈
- 여러 코드를 한데 묶어 다른 곳에서 재사용 할 수 있는 코드 모음
- 보통 비슷한 기능을 하는 함수나 큰 기능을 수행 하는데 필요한 일련의 함수와 데이터가 포함
모듈 사용하기
- import 명령은 내장 모듈을 현재 이름공간으로 가져옴
1. math모듈
- 수학과 관련된 작업을 처리해야 할 때 사용
- dir() 함수를 사용하면 모듈에 어떠한 함수, 데이터가 정의 되있는지 알 수 있음
import math
print("math.pow(2, 10):", math.pow(2, 10))
print("math.log(100):", math.log(100))
print("math.pi:", math.pi)
print("dir(math):", dir(math))
math.pow(2, 10): 1024.0
math.log(100): 4.605170185988092
math.pi: 3.141592653589793
dir(math): ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
2. FTP
- 예제 생략
3. 그 밖의 모듈
- 문자열, 날짜, 시간, 수학, 분수, 십진법, 랜덤, 파일, sqllite3, os, sys, threading, unites, xml, email, http
- 200여개의 모듈이 존재
- 표준 라이브러리에 대한 설명: https://docs.python.org/3/library/index.html 참조
4. 모듈을 사용하는 이유
1) 코드의 재사용
- 자주 사용되는 기능을 모듈로 구현하여 사용하면 반복적으로 사용할 필요가 없음
- 다음 프로그램 구현에도 모듈을 추가하여 재사용할 수 있음
2) 코드를 이름 공간으로 구분하고 관리
- 모듈은 기본적으로 자기 자신을 이름으로 하는 이름 공간을 가짐
- 한정: 모듈을 import 하면 이름공간이 생성 되고 모듈명.attibute_name과 같은 형식으로 모듈의 함수나 어트리뷰트(데이터)를 사용 할 수 있음
- 함수나 데이터가 이름이 똑같아서 충돌하는 것을 방지 할 수 있음
모듈 만들기
- 모듈을 만든다는 것 = 파일을 만든다는 것, 모듈이 파일로 저장 되기 때문에..
1) 모듈: simpleset.py
from functools import*
def intersect(*ar):
"교집합"
return reduce(__intersectSC, ar)
def __intersectSC(listX, listY):
setList = []
for x in listX:
if x in listY:
setList.append(x)
return setList
def difference(*ar):
"차집합"
setList = []
intersectSet = intersect(*ar)
unionSet = union(*ar)
for x in unionSet:
if not x in intersectSet:
setList.append(x)
return setList
def union(*ar):
"합집합"
setList = []
for item in ar:
for x in item:
if not x in setList:
setList.append(x)
return setList
2) 모듈 동작 테스트
- 모듈이 제대로 import되었는지 dir()로 확인
import simpleset
print("dir(simpleset):", dir(simpleset))
dir(simpleset): ['WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', '__builtins__', '__cached__', '__doc__', '__file__', '__intersectSC', '__loader__', '__name__', '__package__', '__spec__', 'cmp_to_key', 'difference', 'intersect', 'lru_cache', 'partial', 'partialmethod', 'reduce', 'singledispatch', 'total_ordering', 'union', 'update_wrapper', 'wraps']
setA = [1, 3, 7, 10]
setB = [2, 3, 4, 9]
print("setA:", setA, "setB:", setB)
setA: [1, 3, 7, 10] setB: [2, 3, 4, 9]
print("simpleset.union(setA, setB):", simpleset.union(setA, setB))
simpleset.union(setA, setB): [1, 3, 7, 10, 2, 4, 9]
print("simpleset.intersect(setA, setB, [1, 2, 3]):",
simpleset.intersect(setA, setB, [1, 2, 3]))
simpleset.intersect(setA, setB, [1, 2, 3]): [3]
모듈의 경로
- 이름만으로 임포트 되게하려면 모듈 검색 경로에 모듈 파일이 있어야 함
- 프로그램이 실행된 홈 디렉토리 -> PYTHONPATH 환경변수 -> 표준 라이브러리 디렉터리 순서로 모듈을 찾음
1. 프로그램이 실행된 홈 디렉토리
2. PYTHINPATH에 등록
1) .bash_profile에 path 추가
2) eclipse에 path 추가
3. 표준 라이브러리 디렉터리
1) sys.path
- 모듈 검색 경로 목록을 리스트 형식으로 관리
import sys
print("sys.path:", sys.path)
sys.path: ['/Users/eunguru/Source/Python/Module/src', '/Users/eunguru/Source/Python/Module/src', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/plat-darwin', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python34.zip']
2) sys.path에 경로를 동적으로 추가/삭제 (테스트를 위해 /Users/eunguru/Source/Test 추가/삭제)
sys.path.append("/Users/eunguru/Source/Test")
print("sys.path:", sys.path)
sys.path: ['/Users/eunguru/Source/Python/Module/src', '/Users/eunguru/Source/Python/Module/src', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/plat-darwin', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python34.zip', '/Users/eunguru/Source/Test']
sys.path.remove("/Users/eunguru/Source/Test")
print("sys.path:", sys.path)
sys.path: ['/Users/eunguru/Source/Python/Module/src', '/Users/eunguru/Source/Python/Module/src', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/plat-darwin', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages', '/Library/Frameworks/Python.framework/Versions/3.4/lib/python34.zip']
모듈 임포트
- 파이썬에서는 import 구문을 어디서나(함수나 제어문 안에서도) 사용 가능
def loadMathMod():
print("import math")
import math
print("dir(math):", dir(math))
loadMathMod()
import math
dir(math): ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
1. 모듈 임포트
1) import 모듈이름
2) from <모듈> import <어트리뷰트>
- <모듈>안에 정의된 어트리뷰트 중 이름에 해당하는 어트리뷰트를 현재의 이름공간 안으로 임포트
- 임포트된 어트리뷰트는 모듈이름.어트리뷰트이름 같은 형식으로 쓰지 않고 바로 참조 가능
from simpleset import union
print("union([1, 2, 3], [3], [3, 4]):", union([1, 2, 3], [3], [3, 4]))
union([1, 2, 3], [3], [3, 4]): [1, 2, 3, 4]
Traceback (most recent call last):
File "/Users/eunguru/Source/Python/Module/src/Module.py", line 39, in <module>
print("intersect([1, 2], [1]):", intersect([1, 2], [1]))
NameError: name 'intersect' is not defined
- 만약 새로 임포트 되는 이름이 이미 이름공간에 있는 이름인 경우, 기존 이름들이 새로 임포트된 이름들로 대체됨
기존 함수가 사라질수 있으므로 주의!
def union(a):
print(a)
print("union:", union)
union: <function union at 0x1018aa048>
union("test")
test
# simpleset 모듈에서 union 이름을 가진 함수를 임포트
from simpleset import union
# 주소가 변경
print("union:", union)
union: <function union at 0x1018a1f28>
# simpleset 모듈의 함수가 실행
print("union(\"test\"):", union("test"))
union("test"): ['t', 'e', 's']
3) from <모듈> import *
- 모듈내 이름 중 밑줄(_)로 시작하는 어트리뷰트(데이터, 함수)를 제외하고 모든 어트리뷰트를 현재의 이름공간으로 임포트
- 모듈 내부에서만 쓰이고 외부에서는 안쓰이는 함수나 데이터일 경우 이름을 밑줄로 시작하면 코드 충돌 확률 감소, 이름공간에 모듈내의 함수가 쓸데없이 임포트 되는 것을 방지
import simpleset
print("dir(simpleset):", dir(simpleset))
dir(simpleset): ['WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', '__builtins__', '__cached__', '__doc__', '__file__', '__intersectSC', '__loader__', '__name__', '__package__', '__spec__', 'cmp_to_key', 'difference', 'intersect', 'lru_cache', 'partial', 'partialmethod', 'reduce', 'singledispatch', 'total_ordering', 'union', 'update_wrapper', 'wraps']
from simpleset import *
print("dir():", dir())
dir(): ['WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'cmp_to_key', 'difference', 'intersect', 'loadMathMod', 'lru_cache', 'math', 'partial', 'partialmethod', 'reduce', 'singledispatch', 'sys', 'total_ordering', 'union', 'update_wrapper', 'wraps']
4) import <모듈> as <별칭>
- 모듈 이름을 별칭으로 변경하여 임포트
- 모듈 이름이 길거나 모듈을 다른 이름으로 참조하고자 할 때 사용
import xml.sax.handler as handler
print("handler:", handler)
handler: <module 'xml.sax.handler' from '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/xml/sax/handler.py'>
모듈 임포트 파헤치기
1. 모듈 임포트시 모듈 실행 단계
- sys.path에 등록된 디렉터리에서 모듈을 찾음
- 모듈의 바이트 코드가 있으면 바로 임포트
- 모듈의 바이트 코드가 없으면 인터프리터를 이용해 해당 모듈의 코드를 바이트 코드를 만든 후 모듈 파일이 존재하는 디렉터리에 저장
(예: 모듈 simpleset.py 바이트 코드 simpleset.pyc)
- 바이트 코드는 모듈이 임포트 될때 인터프리팅 되지 않고 바로 메모리에 로딩, 임포트가 더 빨라짐
- 바이트 코드는 모듈의 내용이 변경되지 않는 이상 재생성 되지 않음
- 모듈이 인포트 되면 어트리뷰트들을 현재의 이름 공간으로 가져오거나 모듈의 이름을 현재 이름 공간으로 가져옴
- 코드를 메모리에 로딩한 후 모듈의 코드가 실행
1) 예제
- 모듈: testmodule.py
print("test module")
defaultvalue = 1
def printDefaultValue():
print("defaultvalue:", defaultvalue)
- 모듈 동작 테스트
import testmodule
test module
testmodule.printDefaultValue()
defaultvalue: 1
2) 예제 2
- 모듈이 임포트 되어 모듈 코드가 로딩되면 프로그램이나 파이썬 인터프리터가 끝나기 전까지 변경되지 않음
- 모듈 변경
print("hello world")
defaultvalue = 2
def printDefaultValue():
print("defaultvalue:", defaultvalue)
- 다시 모듈 임포트
import testmodule
test module
testmodule.printDefaultValue()
defaultvalue: 1
* 해당 코드는 IDLE에서 테스트 했음, PyDev는 자동적으로 인터프리터가 다시 시작되는지 변경된 값이 출력
- IDEL 또는 파이썬 인터프리터 종료 후 재시작
import testmodule
hello world
testmodule.printDefaultValue()
defaultvalue: 2
3) 이미 임포트 된 모듈을 다시 임포트 시키는 예제
import testmodule
import imp
imp.reload(testmodule)
hello world
4) 모듈에 대한 레퍼런스 예제
- 파이썬에서는 모든것이 객체
- 모듈이 임포트 되면 코드가 메모리에 로딩되면서 레퍼런스를 전달해줌
- 모듈은 메모리에 하나만 로딩, 로딩된 모듈을 참조하는 여러개의 레퍼런스가 생성될 수 있음
import testmodule as imp1
hello world
import testmodule as imp2
print("dir():", dir())
dir(): ['WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'cmp_to_key', 'difference', 'handler', 'imp1', 'imp2', 'intersect', 'loadMathMod', 'lru_cache', 'math', 'partial', 'partialmethod', 'reduce', 'singledispatch', 'sys', 'total_ordering', 'union', 'update_wrapper', 'wraps']
imp1.printDefaultValue()
defaultvalue: 2
imp1.defaultvalue = 100
imp2.printDefaultValue()
defaultvalue: 100
'__main__'을 사용한 유용한 팀
1. 터미널에서 모듈을 직접 실행
- 모듈: mymod.py
print("my module")
my module
2. 임포트 되었을때와 직접 실행 했을때 다른 동작을 하게 하는 방법
- 파이썬에서는 별도 함수나 값을 제공하지 않음
- __name__ 어트리뷰트를 이용해서 구분 할 수 있음, __name__값이 달라지기 때문에 모듈이 임포트 될 때 혹은 직접 실행 되었을때 각각 다른 코드를 실행 할 수 있음
1) __name__값 확인 예제
- 수정된 모듈
print("my module")
print(__name__)
a. 직접 실행시 결과
my module
__main__
b. 임포트 시 결과
- 모듈 임포트 코드, 결과
import mymod
mymod.__name__
my module
mymod
2) __name__을 사용해 메인으로 코드가 실행 되었을 때와 모듈을 임포트 했을때 다르게 실행 되는 예제
print("my module")
if __name__ == '__main__':
print("모듈을 직접 실행했음.")
else:
print("모듈을 임포트 했음.")
a. 직접 실행 시 결과
my module
모듈을 직접 실행했음.
b. 임포트 시 결과
import mymod
mymod.__name__
my module
모듈을 임포트 했음.
3. __name__을 이용한 구분 방법 활용
- 모듈을 개발할 때 사용
- 모듈을 수정하거나 코드를 추가할 때마다 임포트해서 테스트 코드를 수행하는 것보다 직접 실행 했을 때 테스트를 수행하면 바로 테스트 결과 확인 가능
- IDLE이나 파이썬 인터프리터를 종료 후 재실행 하지 않아도 됨(개발 효율성 증가)
- 예제: 모듈 testmodule2.py
defaultValue = 0
def printDefaultValue():
print("defaultValue:", defaultValue)
if __name__ == '__main__':
# test code
print("hello world")
defaultValue = 100
printDefaultValue()
hello world
defaultValue: 100
패키지
- 여러개의 모듈을 하나로 묶어야 되는 경우가 필요
- 패키지는 모듈 이름에 "."을 붙여서 파이썬 모듈 이름공간을 구조화 하는 방법
- 패키지 디렉토리 안에는 __init_.py파일이 존재
- __init__.py: 패키지를 초기화 하는 파일
1. 패키지 임포트 예제
- xml.dom은 xml 패키지 안에 dom이라는 하위 모듈이 있음을 의미
1) xml 디렉터리에 있는 __init__.py 내용
- 20번째 구문은 모듈을 임포트 할때 어떤 모듈을 임포트 할지를 정의
2) __all__ 구문에서 dom 모듈 삭제후 임포트 시도 예제
a. dom 삭제
b. 임포트 시도
- __all__은 import *을 실행할 때 포함할 하위 패키지 목록을 나타냄
3) 패키지 임포트
- 모듈을 임포트 할 때와 마찬가지로 패키지 임포트 시에도 __init__.py가 실행
- __version__, _MINIMUM_XMLPLUS_VERSION 변수들이 메모리에 할당 되고 값이 저장
* 책에는 예제가 나왔는데.. 실제 __init__.py에는 변수들이 없음. 확인해보겠음
2. 패키지 임포트 주의 사항
- 패키지를 임포트 했을때 해당 패키지의 하위 패키지는 자동으로 임포트 되지는 않음
import xml
print("xml:", xml)
xml: <module 'xml' from '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/xml/__init__.py'>
print("xml.dom:", xml.dom)
Traceback (most recent call last):
File "/Users/eunguru/Source/Python/Module/src/Module.py", line 86, in <module>
print("xml.dom:", xml.dom)
AttributeError: 'module' object has no attribute 'dom'
print("xml.dom.getDOMImplementation:", xml.dom.getDOMImplementation)
Traceback (most recent call last):
File "/Users/eunguru/Source/Python/Module/src/Module.py", line 87, in <module>
print("xml.dom.getDOMImplementation:", xml.dom.getDOMImplementation)
AttributeError: 'module' object has no attribute 'dom'
- xml.dom을 임포트 하도록 수정
import xml.dom
print("xml:", xml)
xml: <module 'xml' from '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/xml/__init__.py'>
print("xml.dom:", xml.dom)
xml.dom: <module 'xml.dom' from '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/xml/dom/__init__.py'>
print("xml.dom.getDOMImplementation:", xml.dom.getDOMImplementation)
xml.dom.getDOMImplementation: <function getDOMImplementation at 0x10220b158>
3. 패키지 안에서 패키지 안의 모듈 참조하기
- sound 패키지
sound/
__init__.py
formats/
__init__.py
wavread.py -> 현재 작성하는 모듈
auread.py
auwrite.py
...
effects/
__init__.py
echo.py
filters/
__init__.py
equalizer.py
1) 작성하는 모듈이 formats 하위 모듈 wavread.py 일 때,
a. auread 모듈을 임포트, 참조하는 모듈이 같은 디렉터리에 있거나, 하위 디렉터리에 있을 경우
from auread import import *
b. equalizer 모듈을 임포트, 참조해야 하는 모듈이 상위의 다른 디렉터리에 있는 경우
from sound.filters.equalizer import equalizer
2) .을 사용해서 현재 패키지와 부모패키지 참조
- effects 아래의 패키지에 포함된 모듈은 아래의 방법을 참조
a. 현재 디렉터리에서 echo 모듈을 임포트
from . import echo
b. 부모 디렉터리에 있는 모듈중 format 모듈을 가져옴
from .. import formats
c. 부모 디렉터리 모듈 중 filters의 equalizer 모듈을 임포트
from ..filters import import equalizer
'컴&프로그래밍 > Python' 카테고리의 다른 글
13. 파일시스템 (0) | 2015.07.02 |
---|---|
9. C/C++와 연동 (3) | 2015.03.14 |
8. 입출력 (0) | 2015.01.14 |
7. 예외처리 (0) | 2015.01.02 |
Mac OS X Yosemite에서 PyCharm 설치 후 실행 (0) | 2014.12.27 |
5. 클래스 (0) | 2014.12.20 |
4. 제어 (0) | 2014.12.19 |
Google Python Tutorial - Basic Python Exercises #2 List (0) | 2014.12.11 |
Google Python Tutorial - Basic Python Exercises #1 String (0) | 2014.12.05 |