Modules and Packages¶
Module¶
쉽게 생각하면 Python code 로 구성된 file .py
자체를 가리킨다.
- Module은 import될 때 각각 고유의 namespace를 가지므로, Module은 일종의 Namespace이기도 함.
- Python에서 module은 확장자가
.py
인 파일을 가르킴 ( python code를 내용으로 가지는 file ). - 모든
.py
file들은 python에서 module로서 사용가능함.
Python에서 Module은 code의 재사용을 위해 사용 되며,
일반적으로 module들이 모여 하나의 프로그램이 된다.
code의 재사용 이란,
이전에 정의한 variable과 function, class 등을 다시 code로 정의하지 않고 다시 사용하는 것 을 의미함.
module이 없다면 이전에 작성한 code들을 매번 copy and paste 시키거나 기억하고 다시 typing을 해야할 것이다.
code의 재사용을 위해 Python은 이전에 구현했거나 다른 이가 구현한 .py
파일의 이름으로
해당 module (.py
를 가르킴)을
import
statement를 사용하여 import한다.
ds_cal.py
라는 file에 있는 code를 사용하고 싶은 경우,ds_cal
module을 import한다.import ds_cal
과 같은import
statement를 이용함.- import하면
ds_cal
이라는 variable이 만들어지며 이는module
class (or type)의 object를 참조하게 된다.
Python에서는 이미 standard library로
- built-in module 을 제공하고 있음.
- (Python의 built-in function들은
__builtins__
라는 모듈에 속함)
이 외에도
- Third party에서 만든 library의 module들과
- 개발자가 만든 본인의 module들도 import 가능하다.
Note: Module Search Path
module
을 import할 때, 해당module
을 읽어와야하는데 이 경우 Module Search Path 를 참고하여 python은 module을 읽어들임.- Module Search Path 에 기재된 path들에서
module
의 이름을 기준으로module
을 읽어들임 (가장 먼저 위치한 path의module
에 우선권이 있음).- 기본적으로 현재 작업 디렉토리가 포함되므로 이를 이용하여
module
에 대해 익히고, 다른 path의module
들을 사용하기 위해 Module Search Path 를 수정하는 방법은 다음 URL을 살펴본다: Module Search Path and sys.path.
참고로
- 흔히, import가 되는
.py
파일을module
이라고 부르고 - python interpreter에게 수행되기 위해 인자로 넘겨지는
.py
파일은 main program 혹은 main script 라고 불린다.
참고로
__name__
은.py
파일 즉module
내에서 Python interpreter가 해당module
에 할당한 이름, 즉 자기자신의module name
을 값으로 가지는 global variable임.
해당 main script로 동작하는 경우엔__main__
이라는 문자열을 값으로 가짐.
다음의 예는 ds_cal.py
를 module
로 import하는 ds_run.py
를 통해 간단한 module
사용법을 보여준다.
ds_cal.py
와ds_run.py
는 모두 같은 directory에 위치함.- 이 두 파일이 있는 directory가 current working directory임.
#!/bin/env python
# ds_run.py 파일 : main script file.
import ds_cal # 모듈을 import
def main():
while True:
try:
a_str = input('Enter the first operand:')
a = float(a_str)
b_str = input('Enter the second operand:')
b = float(b_str)
r = ds_cal.ds_addition(a, b)
print(f'result = {r}')
break
except ValueError as ve:
print('[ValueError] Invalid Input! Try again!')
if __name__ == '__main__':
main()
import ds_cal
을 통해ds_cal.py
를 파일명인ds_cal
이라는 이름의 module로 사용함.- 이를 통해 main script파일에서는
ds_cal.py
파일의 global scope에 있는 attribute들에 접근을 할 수 있음. - 실제로
ds_cal.ds_addition(a, b)
를 호출하여 그 결과를r
에 할당함 (모듈ds_cal
은 고유의 namespace를 가지며 해당 namespace에 접근하기 위해서ds_cal
이라는 모듈명을 prefix로 가짐). module
의 global attribute들에 접근하기위해서는module
이름을 prefix로 사용해야 함(위의 예에서는ds_cal
이 prefix로 사용됨).- 이는
ds_cal
과 같은 import된 module에 대한 Name Space 가 생성되었음을 의미하며, 해당 name space에 모듈의 attribute들이 속하게 됨.
.
operator¶
ds_cal.ds_addition(a, b)
에서 .
(dot)은 일종의 operator 임.
.
의 왼쪽에 있는 variable이 가르키는 object를 찾고,- 해당 object에서
.
의 오른쪽에 있는 name에 해당하는 object(=attribute)를 찾아내어 접근함.
위의 경우, ds_cal
이라는 variable에 할당된 object에서 ds_addition
이라는 function
attribute를 call하게 됨.
import
되는 경우 module
은 execution(수행)이 이루어짐.¶
module의 statement들은
import가 되는 경우에도 역시 수행이 되므로
이를 통해 해당 module의 초기화가 가능함.
- 같은
module
의 import가 여러 번 되어도, 한번만 수행 이 된다 (최초로 import 되는 경우). - 수행이 되면서 해당
module
이 초기화가 이루어짐. - variable과 function의 정의는 당연히 수행이 되어야 하지만
해당 module이 main script로 동작하는 경우만 실행되어야 하는 code들도 수행이 될 수 있음.
# echo.py
if __name__ == '__main__':
# main script로 동작
print(f'main script mode :{__name__}')
else:
# module로 import 인 경우 수행됨.
print(f"this is echo's init part : {__name__}")
위 module은 import되어 수행되는 경우와 main script로 동작하는 경우가 다른 처리가 이루어지도록 되어 있음.
test_echo.py
를 main script로 수행시, echo
모듈에 대한 초기화 부분이 한번만 수행됨을 확인 가능함.
if __name__ == '__main__':
로 시작하는 code block이
main script에서만 수행되는 부분이 된다.
__name__
이 main script로 동작하는 경우에 __main__
문자열을 값으로 가짐.
__name__
variable은 해당 module의 name에 해당하는 문자열을 값으로 가지는 특별한 variable임.
__
로 시작하고 끝나는 object는 Python 언어에서 특별하게 사용되는 object로서 Python 언어에서 정의하고 있는 대상임을 나타내는데 사용 된다.
다시 한번 강조하지만,
- import 문이 동일한 module에 대해 호출이 여러번 되어도 최초 한번만 수행 이 된다.
- 때문에 특정 Python Interpreter Session이 수행되고 있는 동안에 특정 module의 소스코드 자체가 바뀌더라도 해당 변경사항이 반영되지 않는다.
이를 위해서는 importlib
모듈의 reload(모듈명)
function을 이용해야 한다.
자세한 사용법은 다음 URL을 참고하라.
주의: reassignment.¶
Python은 standard library의 module의 attributes에 재할당이 (매우 쉽게) 가능하다는 단점을 가짐.
다음 code는 math
module의 pi
라는 variable에
reassignment가 가능함을 보임.
pi
는 \(\pi\) 의 값을 가져야하는데
이같은 reassignment는 많은 문제의 원인이 될 수 있다.
실제 module에 해당하는 file에서 수정이 일어나진 않고, 단순히 memory상에서
math
의 namespace의pi
라는 이름이 가르키는 object가 바뀐 것이므로 해당 Python interpreter의 session에서만72
라는 값을 의미하게 되고, 다른math
모듈을 사용하는 session에서는 문제가 없다.
Python에서는 이처럼 고정되어야 하는 상수를 freeze
할 수가 없다는 단점을 가지고 있음.
as
를 통한 alias(별칭) 사용하기.¶
앞서 예의 import
statement에서 import된 모듈에 접근은 ***모듈 파일의 name(이름)***을 통해서 이루어짐.
해당 이름이 너무 긴 경우 나 관례적으로 사용되는 별칭 이 있는 경우엔
alias를 지정 해주어 모듈의 attribute에 접근함.
해당 alias를 지정하는 import
statement는 다음과 같음.
import ds_cal
로 import한 경우ds_cal.ds_addition(a, b)
.import ds_cal as dc
로 Alias를dc
로 지정한 경우dc.ds_addition(a, b)
로 접근 가능함.
Python 에서 가장 유명한 alias 중 하나는 NumPy 를 가르키는
np
임.
NumPy를 사용하는 경우,import numpy as np
가 가장 많이 사용됨.
다른 하나는matplotlib.pyplot
의 Alias인plt
임.
pyplot
을 사용하는 경우,import matplotlib.pyplot as plt
가 가장 많이 애용됨.
원하는 attribute만 import하기.¶
현재 ds_cal.py
모듈에서 필요한 attribute는 바로 ds_addition
함수 뿐이라고 가정하자.
이처럼 필요한 attribute의 수가 적고 이름을 정확히 알고 있는 경우
다음과 같이 명시적으로 지정하여 필요한 기능만을 import할 수 있음.
이 경우의 최대 장점은 모듈명에 해당하는 prefix가 필요없다 는 점임.
#!/bin/env python
# ds_run02.py 파일 : main script file.
from ds_cal import ds_addition # ds_addition만 지정하여 import
def main():
while True:
try:
a_str = input('Enter the first operand:')
a = float(a_str)
b_str = input('Enter the second operand:')
b = float(b_str)
r = ds_addition(a, b) # module prefix 필요없음.
print(f'result = {r}')
break
except ValueError as ve:
print('[ValueError] Invalid Input! Try again!')
if __name__ == '__main__':
main()
from 모듈명 import Attribute0, Attribute1
과 같이
하나의 module에서 여러 Attribute들을 import할 수 있음.
특정 module의 모든 attribute 모조리 import¶
아래와 같은 import문을 사용할 경우,
ds_cal.py
파일의
모든 global scope의 attribute들을 import한다.
장점은
- 가장 편하다는 것으로 prefix가 필요없고,
- import 할 때 필요한 attribute들을 입력해주지 않아도 된다는 것임.
정확히 애기하면, 모든 attribute는 아님.
_
로 시작하는 이름을 가지는 attribute들은 import가 이루어지지 않음.
문제는
- 일반적으로 특정 module에서 어떤 attribute들이 있는지 알기 어렵고,
- prefix를 사용하지 않기 때문에 name collusion이 발생하기 쉽다.
해당 code의 동작은 알고는 있어야하지만,
사용은 절대 추천하지 않는다.
Packages¶
Python에서 module
이 .py
파일로 구현되는 것처럼,
package
는 module
들이 포함된 directory로 구현된다.
Python 2.x 의 경우,
__init__.py
가 있어야 했으나
Python 3.x에서는 필요가 없음.하지만 호환성을 위해 빈 파일로라도
__init__.py
를 넣어주는 게 좋음.
package
를 통해 module
들은
- logically 비슷한 것들끼리 구분짓고
- 계층화 할 수 있다.
다음 예제는
사칙연산을 구현한 ds_cal.py
를 farith
package에 두고,
기본 삼각함수 관련 함수를 제공하는 ds_cal.py
를 ftri
package로 나누어 제공하면서
이들을 ds_run03.py
에서 모듈로 사용하는 것을 보여줌.
- 같은 파일명임에도 package를 다르게 함으로서 구분이 가능해짐.
- 이 경우
import
문에서 package 명들도 prefix로 추가를 해줘야함.
# ./farith/ds_cal.py
def ds_addition(a,b):
return a+b
def ds_subtraction(a,b):
return a-b
def ds_multiplication(a,b):
return a*b
def ds_division(a,b):
return a/b
# ./ftri/ds_cal.py
import math
def ds_cos(rad):
return math.cos(rad)
def ds_sin(rad):
return math.sin(rad)
#!/bin/env python
# ds_run03.py
import farith.ds_cal as fundamental
import ftri.ds_cal as tri
def main():
while True:
try:
a_str = input('Enter the first operand:')
a = float(a_str)
b_str = input('Enter the second operand:')
b = float(b_str)
print(f'{a}+{b}={fundamental.ds_addition(a,b)}')
rad = float(input('Enter the radian to get the value of cosine:'))
print(f'cos of {rad}={tri.ds_cos(rad)}')
break
except ValueError as ve:
print(ve)
if __name__ == '__main__':
main()
Namespace Package¶
여러 독립적인 패키지들을 하나의 "논리적인 패키지" (단순히 하나의 namespace 에 속하도록 해주는 역할의 패키지) 처럼 보이게 해주기 위해 제안된 도구.
- 대규모 프로젝트에서 독립적인 패키지 관리가 가능함.
namespace package
의 경우,
- 물리적으로 다른 경로(각각의
sys.path
에 item이어야함.)에 있더라도, - 같은 패키지명을 공유할 경우 하나의 package로 Python에서 처리됨.
- 여러 다른 개발그룹이 동일한 패키지를 동시에 확장하여 개발하는 것을 가능하게 함.
이 경우, 같은 패키지명을 공유하는 모든 subdirectory 내에 __init__.py
가 있어선 안됨 (Python 3.3 이상부터만 사용가능함).
sys.path
에 정의된 경로들을 탐색하면서 namespace package로 인식된 모든 디렉토리들을 처리할 때, 동일한 이름의 디렉토리는 같은 "논리적 패키지" 로 병합함.
다음의 링크에서 예를 들어 설명하고 있으니 참고할 것:
Summary¶
- Module은 하나의
.py
파일 로 묶여있는variable
,function
그리고class
등의 object의 Collection을 가르킴:- 흔히
.py
파일 하나를 module이라고 부른다. - Module은 고유의 Namespace를 가지며, 관련있는 object들을 묶어서 재사용이 가능하도록 해줌.
- 흔히
- Package는 관련이 있는 module들을 가지고 있는 subdirectory 에 해당:
- module들의 이름들을 가지고 있는(포함하는) 일종의 namespace를 제공함.
- Module과 package 들이 모여서 Library 를 구성함.
References¶
- Python (3.11.4) 공식설명서6. 모듈
- Module Search Path