라이브러리와 프레임워크
- 라이브러리(library) : 정상적인 제어를 하는 모듈을 라이브러리 라고 한다.
- 프레임워크(framework) : 제어의 역전이 발생하는 모듈을 프레임워크 라고 한다.
제어의 역전(IoC : Inversion of Control)
라이브러리 : 정상적인 제어
라이브러리는 모듈의 기능을 개발자가 직접 호출하는 것이다.
from math import sin, cos, tan, floor, ceil
print(sin(1))
print(cos(1))
print(tan(1))
print(floor(2.5))
print(ceil(2.5))
프레임 워크 : 제어의 역전
직접적으로 무언가를 진행하는 코드는 따로 없다.

Flask 모듈이 제공하는 명령어를 실행하면 코드를 직접 실행하지 않아도 Flask 모듈 내부에서 서버를 실행한 뒤 지정한 파일을 읽어들여 적절한 상황에 스스로 실행하는 상황이다.
이처럼 모듈이 개발자가 작성한 코드를 자동으로 실행하는 형태의 모듈을 프레임워크 라고 부른다.

개발자가 모듈의 함수를 호출하는 것이 일반적인 제어, 반대로 개발자가 만든 함수를 모듈이 실행시키는 것이 제어의 역전이다.
따라서 프레임워크와 라이브러리는 제어 역전 여부로 구분할 수 있다.
모듈 만들기
파이썬 파일을 만들고 외부에서 읽어들이게 하면 그것을 모듈 이라고 부른다.
모듈을 구조화해서 패키지(거대한 모듈)을 만들 수 있다.
1. 모듈 폴더, 파일 만들기
1 - 1. module_basic 폴더 생성
1 - 2. module_basic 폴더 안에 test_module.py 파일 생성
# test_module.py
PI = 3.141592
def number_input():
output = input("숫자 입력 : ")
return float(output)
def get_circumference(radius):
return 2 * PI * radius
def get_circle_area(radius):
return PI * radius * radius
1 - 3. module_basic 폴더 안에 main.py 파일 생성
# main.py
import test_module as test
radius = test.number_input()
print(test.get_circumference(radius))
print(test.get_circle_area(radius))
__name__ == __main__
__name__이란?
파이썬 코드 내부에서는 __name__ 이라는 변수를 사용할 수 있다.
프로그래밍 언어에서는 프로그램의 진입점을 엔트리 포인트(entry point) 또는 메인(main) 이라고 부른다.
메인 내부에서의 __name__ 변수 값은 __main__ 이다.
print(__name__)
# 결과값
# __main__
모듈의 __name__
엔트리 포인트가 아니지만 엔트리 포인트 파일 내에서 import 되었기 때문에 모듈 내의 코드가 실행된다.
모듈 내부에서 __name__을 출력하면 모듈의 파일 이름이 출력된다.
1. module_main 폴더 생성
2. module_main 폴더 안에 test_moduel.py 파일 생성
print("모듈의 __name__을 출력하기")
print(__name__)
print()
3. module_main 폴더 안에 main 파일 생성
import test_module
print("메인의 __name__을 출력하기")
print(__name__)
print()
# 결과값
# 모듈의 __name__을 출력하기
# test_module
# 메인의 __name__을 출력하기
# __main__
위의 결과를 보면 엔트리 포인트 파일에서는 "__main__" 을 출력하지만 모듈 파일에서는 모듈 이름을 출력하는 것을 볼 수 있다.
__name__ 활용
엔트리 포인트 파일 내부에서 __name__ 이 "__main__" 이라는 값을 갖는다는 것을 활용해서 현재 파일이 모듈로 실행되고 있는 지, 엔트리 포인트로 실행되고 있는지 확인할 수 있다.
위에서 만들었던 module_basic 에 담긴 test_module.py 파일 내용 수정하기
PI = 3.141592
def number_input():
output = input("숫자 입력 : ")
return float(output)
def get_circumference(radius):
return 2 * PI * radius
def get_circle_area(radius):
return PI * radius * radius
# 활용 예시
print("get_circumference(10) :", get_circumference(10))
print("get_circle_area(10) :", get_circle_area(10))
이후 module_basic 폴더에 담긴 main.py 파일 실행하기

모듈에서 활용 예시로 사용했던 코드까지 출력된다.
사실 해당 코드는 모듈로 사용될 때 출력이 되면 안된다...
이 때 해당 파일이 엔트리 포인트인지 구분하는 코드를 활용하면 된다.
module_basic 폴더 안에 test_module.py 파일 내용 수정하기
PI = 3.141592
def number_input():
output = input("숫자 입력 : ")
return float(output)
def get_circumference(radius):
return 2 * PI * radius
def get_circle_area(radius):
return PI * radius * radius
# 활용 예시
if __name__ == "__main__":
print("get_circumference(10) :", get_circumference(10))
print("get_circle_area(10) :", get_circle_area(10))
이후 module_basic 폴더에 담긴 main.py 파일 실행하기

위의 코드처럼 내용을 수정한 이후 다시 main 파일을 실행하면 테스트용으로 사용되었던 print 함수는 실행되지않는다.
패키지
모듈이 모여서 구조를 이룬 것을 패키지 라고 한다.
pip는 Python Package Index 의 줄임말로, 패키지 관리 시스템(package Management System) 이라고 한다.
패키지 만들기
구성
- module_package(폴더)
- test_package(폴더) : 패키지로 사용할 폴더
- module_a.py : 모듈A 로 사용할 파이썬 파일
- module_b.py : 모듈B 로 사용할 파이썬 파일
- main.py : 엔트리 포인트로 사용할 파이썬 파일
- test_package(폴더) : 패키지로 사용할 폴더

module_a.py 파일 내부 코드
variable_a = "a 모듈의 변수"
module_b.py 파일 내부 코드
variable_b = "b 모듈의 변수"
main.py 파일 내부 코드
# 패키지 내부의 모듈을 읽어들임
import test_package.module_a as a
import test_package.module_b as b
# 모듈 내부의 변수를 출력
print(a.variable_a)
print(b.variable_b)
# 결과값
# a 모듈의 변수
# b 모듈의 변수
__init__.py 파일
패키지를 읽어올 때 어떤 처리를 수행해야 하거나 패키지 내부의 모듈들을 한꺼번에 가져오고 싶을 때 패키지 폴더 내부에 __init__.py 파일을 만들어서 사용해야 한다.
해당 폴더가 패키지임을 알려주고 패키지와 관련된 초기화 처리를 하는 파일이다.
__all__ 이라는 이름의 리스트를 만들면 이 리스트에 지정된 모듈들이 from 패키지 * 를 할 때 전부 읽어 들여진다.
main.py 파일 코드 수정하기
# 패키지 내부의 모듈을 모두 읽어들임
from test_package import *
# 모듈 내부의 변수를 출력
print(module_a.variable_a)
print(module_b.variable_b)
이후 main.py 파일을 실행하면 에러가 발생하게 된다.

그 이유는 방금 위에서 말한 것 처럼 __init__.py 파일이 없어서 * 을 사용할 수 없기 때문에 패키지를 제대로 import 하지 못한다.
__init__.py 파일 생성
# from test_package import * 로 모듈을 읽어들일 때 가져올 모듈
__all__ = ["module_a", "module_b"]
# 패키지를 읽어 들일 때 처리를 작성할 수도 있음
print("test_package를 읽어들였습니다.")
파일 생성 이후 main.py 파일 실행
# 패키지 내부의 모듈을 모두 읽어들임
from test_package import *
# 모듈 내부의 변수를 출력
print(module_a.variable_a)
print(module_b.variable_b)
# 결과값
# test_package를 읽어들였습니다.
# a 모듈의 변수
# b 모듈의 변수
__init__ 파일을 생성한 이후 main.py 파일을 실행시키면 오류가 나지 않고 정상적으로 작동하는 것을 볼 수 있다.