도서 구입 지출 합계
60분 안팎
학습 목표
입력·계산·출력 계약을 함수로 표현합니다.
개념
왜 돈은 단위부터 정하는가
도서 구입 지출은 쪽수와 다른 수량입니다. 쪽수 80과 금액 8000을 같은 합계 변수에 넣으면 숫자 계산은 되지만 의미가 없습니다. 이번 계약은 할인과 세금을 이미 반영한 최종 구입 금액을 정수 원 단위로 받습니다. 단가와 권수를 곱하는 과제는 아닙니다. 0원은 증정받은 책의 유효한 금액입니다. 이를 빈 입력과 구별해 목록에 남깁니다. 금액 합계는 모든 기록의 원 단위 지출을 더한 정수입니다.
입력·계산·출력의 세 경계
첫 줄 n과 다음 n개의 금액 줄을 입력부에서 읽어 정수 목록으로 만듭니다. total_cost(amounts)는 입력창을 읽지 않고 전달받은 목록만 계산합니다. 호출부는 반환값을 print로 한 번 출력합니다. 함수 안에서 input을 호출하면 같은 계산을 테스트할 때마다 키보드 입력이 필요합니다. 함수를 입력부와 분리하면 빈 목록과 큰 금액도 직접 전달해 확인할 수 있습니다. 화면 안내가 필요해져도 계산 함수를 바꿀 이유가 없어집니다.
정수 원 단위 계약을 지킨다
이번에는 소수 원을 허용하지 않으므로 float를 거치지 않고 int로 읽습니다. int(float(raw))처럼 바꾸면 소수 부분이 잘려 입력 정책을 조용히 바꿀 수 있습니다. 돈에 실수를 쓰면 표현 오차와 반올림 정책도 별도로 정해야 합니다. 이 수업은 정수 최종 금액만 다루므로 할인율 계산을 임의로 추가하지 않습니다. 12,000처럼 쉼표가 있는 표시는 숫자 입력 계약에 없으며 입력에는 12000을 씁니다. 결과 출력에도 쉼표나 원 기호를 붙이지 않습니다.
합계 함수의 작은 책임
total_cost는 total을 0에서 시작해 각 amount를 더하고 반복 밖에서 반환합니다. 0·12000·8000을 받으면 20000이고 호출 뒤 목록은 그대로입니다. 첫 0을 보고 break하면 나머지 지출이 사라집니다. 0을 continue로 건너뛰더라도 합계는 우연히 같을 수 있지만 관측 건수까지 세는 확장에서는 의미가 달라집니다. 모든 값을 계약대로 읽고 더하는 구현이 가장 설명하기 쉽습니다. 빈 목록의 결과 0은 합칠 지출이 없다는 뜻이지 입력 오류를 0으로 숨긴 것이 아닙니다.
잘못된 입력을 0원으로 만들지 않는다
브라우저 실습에서는 0 이상의 정수 금액을 제공합니다. 실제 미션의 여러 건 입력에서는 제공된 해석 코드가 음수와 숫자 문법 오류를 거부합니다. 잘못된 문자열을 변환하지 못했다고 0을 대신 넣으면 실제 무료 도서와 오류를 구별할 수 없습니다. 오류가 어느 입력에서 생겼는지와 거부 기준을 문서로 남깁니다. 오류가 발생한 상태로 합계를 성공처럼 출력하지 않습니다. 예외를 세밀하게 처리하고 기존 기록을 보호하는 방식은 다음 모듈에서 더 연습합니다.
검증은 합계와 원본을 함께 본다
0만 있는 목록, 한 건, 세 건, 같은 금액 여러 건, 큰 정수를 각각 확인합니다. [12000, 12000]은 구매 기록 두 건이므로 24000이며 같은 값이라는 이유로 중복 제거하지 않습니다. total_cost를 연속 호출해도 결과가 누적되지 않아야 합니다. 바깥 전역 total에 계속 더하면 두 번째 결과가 커질 수 있으므로 지역 초기화를 확인합니다. 반환 자료형도 int인지 봅니다. 화면이 20000.0이어도 출력 계약은 20000이므로 계산과 표시를 따로 점검합니다.
금액 예제를 손으로 추적하기
[0, 12000, 8000]을 함수에 전달하면 시작 total은 0입니다. 첫 금액을 더해도 0이고 둘째 금액 뒤에는 12000, 마지막에는 20000이 됩니다. 반환은 세 값을 모두 처리한 뒤 한 번 실행합니다. 첫 금액이 무료라는 이유로 계산을 끝내면 최종 지출이 사라집니다. 구입 금액은 한 기록에 이미 확정된 지출이므로 권수나 쪽수를 다시 곱하지 않습니다. 예제의 12000과 8000은 각각 독립된 기록입니다. 두 값을 합쳐 20000이라는 수량을 얻는 과정과 화면에 그 수량을 쓰는 과정을 구분합니다.
합계가 만족해야 할 관계
빈 금액 목록의 합계는 0입니다. 목록 끝에 0원을 추가하면 합계는 같고 구매 기록 수만 늘어납니다. 끝에 500원을 추가하면 합계는 정확히 500만 늘어납니다. 금액의 순서를 바꾸어도 정수 합계는 같습니다. 이런 관계를 이용하면 정답 한 개만 외우는 대신 구현의 동작을 점검할 수 있습니다. [8000, 12000]과 [12000, 8000]을 각각 계산해 20000인지 보세요. 원본 목록을 정렬할 필요는 없습니다. 합계를 위해 입력 순서를 변경하면 이후 구매 순서 표시에서 불필요한 문제가 생깁니다.
큰 정수와 표시 형식
Python 정수는 고정된 32비트 범위로 제한되지 않으므로 1000000000과 1을 더한 결과는 1000000001입니다. 이 연습의 큰 금액도 float를 거치지 않고 정수로 누적합니다. 다만 실제 시스템의 다른 저장소나 외부 API에는 별도의 수량 제한이 있을 수 있어 그 계약을 확인해야 합니다. 여기서는 브라우저에 명시된 정수 입력과 출력만 다룹니다. 출력은 숫자 한 줄이며 20000원이나 20,000으로 꾸미지 않습니다. 사용자를 위한 금액 표시를 추가하는 경우에도 계산 함수의 정수 반환은 그대로 두고 표시부에서 처리합니다.
오류와 무료 구매를 구분하기
무료 도서 0원은 정상 입력이므로 합계에 포함합니다. 반면 음수나 소수 원을 정상 금액으로 바꾸는 정책은 제공되지 않았습니다. 미션의 입력 해석부는 잘못된 금액을 발견하면 ERR_BATCH를 출력하고 종료 코드 2로 끝냅니다. 그때 SUMMARY 성공 줄을 함께 출력하면 호출자가 실패 결과를 정상 보고서로 오해할 수 있습니다. 계산 함수는 이미 해석된 금액을 받으므로 문자열을 정수로 변환하는 코드를 반복해서 넣지 않습니다. 입력 거부와 정상 합산의 경계를 유지하면 무료 구매와 입력 오류의 의미를 지킬 수 있습니다.
지출 함수를 미션에 연결하기
브라우저의 total_cost는 정수 목록을 순회하지만 미션의 total_cost는 기록 목록의 cost 필드를 읽습니다. 미션에서 각 record에는 제목과 쪽수, 금액, 완료 표시가 함께 있습니다. 금액 합계에는 cost만 더하고 pages나 completed를 섞지 않습니다. 같은 책의 구매가 두 번 기록되면 두 건 모두 합산하는 계약입니다. 취소나 환불, 중복 구매 판정은 이번 범위에 없어 임의로 처리하지 않습니다. 반환한 정수는 제공된 출력부가 SUMMARY의 총금액 위치에 넣습니다. 빈 기록 목록에도 정수 0을 반환하고 입력 기록을 보존합니다.
따라하기
정수 금액 합계
코드를 실행해 반환값을 확인합니다.
def total_cost(amounts):
total = 0
for amount in amounts:
total += amount
return total
amounts = [0, 12000, 8000]
print(total_cost(amounts))
print(amounts)
실행 결과
20000 [0, 12000, 8000]
빈 값과 반복 구매
코드를 실행해 반환값을 확인합니다.
def total_cost(amounts):
total = 0
for amount in amounts:
total += amount
return total
print(total_cost([]))
print(total_cost([12000, 12000]))
실행 결과
0 24000
입력과 계산 연결
개수 3 뒤에 금액을 한 줄씩 입력합니다.
def total_cost(amounts):
total = 0
for amount in amounts:
total += amount
return total
n = int(input())
amounts = []
for index in range(n):
amounts.append(int(input()))
print(total_cost(amounts))
실행 결과
20000
호출 간 초기화
코드를 실행해 반환값을 확인합니다.
def total_cost(amounts):
total = 0
for amount in amounts:
total += amount
return total
print(total_cost([1, 2]))
print(total_cost([1, 2]))
실행 결과
3 3
확인 문제
실습
첫 줄 n 다음 n줄에 0 이상 정수 원 단위 최종 구입 금액이 주어집니다. total_cost를 완성해 정수 합계 한 줄을 출력합니다. 무료 도서는 0, 빈 목록 합계는 0이며 원 기호·쉼표는 출력하지 않습니다.
모범 답안
def total_cost(amounts):
total = 0
for amount in amounts:
total += amount
return total
n = int(input())
amounts = []
for index in range(n):
amounts.append(int(input()))
print(total_cost(amounts))
더 읽기
면접 질문
- 정수 원 단위 지출 합계에서 입력·계산·출력을 어떻게 나누나요?
- 잘못된 금액을 0원으로 바꾸면 어떤 문제가 생기나요?