Python 모듈, import와 argparse를 이용한 CLI 기초
__name__이번 강의가 끝나면 다음을 할 수 있어야 한다.
if __name__ == "__main__"의 역할을 설명할 수 있다.argparse로 간단한 명령행 프로그램을 만들 수 있다.모듈(module)은 Python 코드를 저장한 .py 파일이다. 함수와 클래스를 모듈에 저장하면 다른 프로그램에서 다시 사용할 수 있다.
.py 파일모듈로 나누면 긴 프로그램을 기능별로 정리하고 같은 코드를 여러 프로그램에서 사용할 수 있다.
같은 폴더에 다음 두 파일을 만든다.
def add(a, b):
return a + b
def multiply(a, b):
return a * b
def power(base, exponent):
return base**exponent
import calculator
print(calculator.add(3, 4))
print(calculator.multiply(3, 4))
print(calculator.power(3, 4))
터미널에서 main.py가 있는 폴더로 이동한 뒤 실행한다.
python main.py
예상 출력은 7, 12, 81이다.
모듈 이름과 호출 이름이 모두 calculator로 같은지 확인한다. 파일 이름이 calculator.py이면 import calculator라고 써야 한다.
같은 모듈을 여러 방식으로 불러올 수 있다.
import math
print(math.sqrt(9))
from math import sqrt
print(sqrt(9))
import math as m
print(m.sqrt(9))
처음에는 import math처럼 모듈 이름을 남기는 방식이 함수의 출처를 알아보기 쉽다. from module import *는 이름 충돌이 생길 수 있으므로 사용하지 않는 편이 좋다.
직접 만든 모듈을 불러오지 못한다면 다음을 확인한다.
calculator.py인가?main.py와 calculator.py가 같은 폴더에 있는가?현재 폴더는 터미널에서 다음 명령으로 확인할 수 있다.
pwd # pring working directory
Windows 명령 프롬프트에서는 다음 명령을 사용할 수 있다.
REM current directory
cd
__name__ 다음 코드를 example.py에 저장하자.
def greet(name):
return f"Hello, {name}!"
if __name__ == "__main__":
print(greet("student"))
python example.py로 직접 실행하면 조건문 안의 코드가 실행된다. 다른 파일에서 import example로 불러오면 조건문 안은 실행되지 않는다.
따라서 함수와 클래스를 정의하는 부분과 프로그램을 직접 실행하는 부분을 분리할 수 있다.
명령행 인자(command-line argument)는 프로그램을 실행할 때 함께 전달하는 값이다.
다음 코드를 show_args.py에 저장한다.
import sys
if __name__ == "__main__":
print(sys.argv)
다음과 같이 실행해 보자.
python show_args.py aluminum 27
sys.argv의 첫 번째 원소는 파일 이름이고 그 뒤에 입력값들이 문자열로 저장된다. 간단히 확인할 때는 유용하지만 입력값의 의미와 자료형을 관리하려면 argparse가 더 편리하다.
다음 코드를 square.py에 저장한다.
import argparse
def main():
parser = argparse.ArgumentParser(
description="Calculate the square of an integer."
)
parser.add_argument(
"x",
type=int,
help="integer to be squared",
)
args = parser.parse_args()
print(args.x**2)
if __name__ == "__main__":
main()
도움말과 계산은 각각 다음처럼 실행한다.
python square.py --help
python square.py 3
두 번째 명령은 9를 출력한다. type=int를 지정했기 때문에 입력 문자열을 정수로 변환한다.
import argparse
def main():
parser = argparse.ArgumentParser()
parser.add_argument("x", type=float)
parser.add_argument("y", type=float)
parser.add_argument(
"--operation",
choices=["add", "multiply"],
default="add",
)
args = parser.parse_args()
if args.operation == "add":
result = args.x + args.y
else:
result = args.x * args.y
print(result)
if __name__ == "__main__":
main()
python calculate.py 3 4
python calculate.py 3 4 --operation multiply
첫 명령은 기본 연산인 덧셈 결과 7을, 두 번째 명령은 곱셈 결과 12를 출력한다.
질량과 부피를 입력받아 밀도를 계산하는 프로그램을 만들어 보자. 다음 코드를 density_cli.py에 저장한다.
import argparse
def density(mass_g, volume_cm3):
if volume_cm3 <= 0:
raise ValueError("volume must be positive")
return mass_g / volume_cm3
def main():
parser = argparse.ArgumentParser(
description="Calculate density."
)
parser.add_argument(
"mass",
type=float,
help="mass in g",
)
parser.add_argument(
"volume",
type=float,
help="volume in cm^3",
)
args = parser.parse_args()
rho = density(args.mass, args.volume)
print(f"density = {rho:.3f} g/cm^3")
if __name__ == "__main__":
main()
다음 명령을 실행하면 밀도 2.700 g/cm³가 출력된다.
python density_cli.py 27 10
함수 density는 계산만 담당하고 main은 입력 해석과 출력을 담당한다. 이렇게 역할을 분리하면 계산 함수를 다른 모듈에서도 재사용하기 쉽다.
ModuleNotFoundError: 파일 이름과 현재 폴더를 확인한다.AttributeError: 모듈에 해당 함수가 정의되어 있는지 확인한다.NameError: 변수 이름의 철자가 앞뒤에서 같은지 확인한다.TypeError: 인자의 개수와 자료형을 확인한다.IndentationError: 조건문과 함수 본문의 들여쓰기를 확인한다.오류 메시지의 마지막 줄부터 읽으면 오류 종류와 원인을 찾기 쉽다.
Python 모듈 파일의 확장자를 쓰시오.
tools.py라는 모듈을 불러오는 문장을 쓰시오.
calculator 모듈의 add 함수에 2와 5를 전달하는 표현을 쓰시오.
명령행 프로그램의 사용법을 확인할 때 사용하는 기본 선택 사항은 무엇인가?
argparse에서 입력값을 정수로 변환하도록 지정하는 표현은 무엇인가?
다음 명령에서 명령행 인자 두 개를 쓰시오.
python density_cli.py 27 10
5장 함수 기초에서 작성한 decimal_to_binary(number) 함수를 별도 모듈로 옮기고, 명령행에서 호출하는 프로그램을 작성하시오. 5장에서는 함수의 재사용을, 이번에는 파일 사이의 재사용과 명령행 입력 처리를 연습한다.
같은 폴더에 다음 두 파일을 만든다.
| 파일 | 역할 |
|---|---|
binary_tools.py | decimal_to_binary(number) 함수 정의. 계산만 담당 |
binary_cli.py | 모듈을 가져오고, 명령행 입력을 해석해 결과 출력 |
함수는 양의 정수의 2진수 문자열을 반환하고, 0이면 '0', 음수이면 None을 반환한다. 5장 프로젝트와 동일하게 while, //, %로 변환하며 bin()은 사용하지 않는다.
binary_tools.py에 변환 함수를 정의한다. 이 파일을 import할 때 출력이나 입력 요청이 발생하지 않아야 한다.binary_cli.py에서 import binary_tools로 모듈을 가져오고, binary_tools.decimal_to_binary(...)로 함수를 호출한다.argparse로 위치 인자 number를 받고 type=int를 지정한다.None을 확인하고 parser.error('음수는 지원하지 않습니다.')로 오류를 알린다.main() 함수에 넣고, 메인 가드 아래에서 호출한다.if __name__ == '__main__':
main()
parser.error는 안내를 출력한 뒤 프로그램을 오류 상태로 종료한다. 정수가 아닌 입력이나 필수 인자 누락은 argparse가 처리한다.
터미널에서 두 파일이 있는 폴더로 이동한 뒤 실행한다.
python binary_cli.py 13
기대 출력은 13 -> 1101이다.
| 명령 | 기대하는 동작 |
|---|---|
python binary_cli.py 0 | 0 -> 0 출력 |
python binary_cli.py 32 | 32 -> 100000 출력 |
python binary_cli.py -3 | 음수를 지원하지 않는다는 오류 안내 |
python binary_cli.py abc | 정수 입력이 필요하다는 오류 안내 |
python binary_cli.py | 필수 인자가 없다는 오류 안내 |
python binary_cli.py --help | 사용법과 인자 설명 출력 |
Python에서 import binary_tools와 import binary_cli를 실행했을 때 아무것도 출력되지 않는지도 확인한다.
제출물: 두 Python 파일, 확인 사례별 실행 결과, 그리고 ‘계산 함수와 CLI를 분리한 이유, import와 메인 가드의 역할’에 대한 짧은 설명.