이 페이지의 목차
함수로 프로그램 나누기
코드 예제: Python · C · 예상 50분
학습 목표
- 하나의 문제를 여러 함수로 나누어 설계한다.
- 함수로 구성된 프로그램을 완성하고 동작을 확인한다.
관련 성취기준
- 프그02-05
함수의 개념과 종류, 필요성을 이해하고, 함수 정의 및 사용자 정의 함수를 호출하고 결괏값을 반환하는 프로그램을 작성할 수 있다.
생각 열기 — 한 덩어리로 쓴 프로그램
성적 관리 프로그램을 지금까지 배운 것으로 쭉 이어 쓰면 이렇게 된다.
개수 = int(input())
점수 = []
for _ in range(개수):
점수.append(int(input()))
인원 = len(점수)
합계 = 0
for s in 점수:
합계 += s
평균 = 합계 / 인원
최고 = max(점수)
최저 = min(점수)
print(f"인원 {인원}명")
print(f"평균 {평균:.1f} 최고 {최고} 최저 {최저}")
돌아간다. 그런데 3단원 3차시 생각 열기에서 본 문제가 그대로다 — 평균이 이상하게 나왔을 때 어디를 봐야 하는지 알 수 없다.
3단원의 설계를 코드로
3단원 3차시에서 이 프로그램을 이렇게 나눴다.
| 부품 | 받는 것 | 돌려주는 것 | 하는 일 |
|---|---|---|---|
점수받기 |
없음 (사용자 입력) | 정수 목록 | 점수를 하나씩 받아 목록으로 |
통계내기 |
정수 목록 | 결과 묶음 | 인원·평균·최고·최저를 낸다 |
보여주기 |
결과 묶음 | 없음 (화면 출력) | 정해진 형식으로 찍는다 |
이제 그 설계를 코드로 옮긴다.
def 점수받기():
개수 = int(input())
점수 = []
for _ in range(개수):
점수.append(int(input()))
return 점수
def 통계내기(점수):
return {
"인원": len(점수),
"평균": sum(점수) / len(점수),
"최고": max(점수),
"최저": min(점수),
}
def 보여주기(결과):
print(f"인원 {결과['인원']}명")
print(f"평균 {결과['평균']:.1f} 최고 {결과['최고']} 최저 {결과['최저']}")
보여주기(통계내기(점수받기()))인원 3명 평균 85.0 최고 92 최저 75
#include <stdio.h>
typedef struct { int n; double avg; int high; int low; } Stat;
int read_scores(int a[], int max)
{
int n;
if (scanf("%d", &n) != 1) return 0;
if (n > max) n = max;
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
return n;
}
Stat make_stat(const int a[], int n)
{
Stat s = {n, 0, a[0], a[0]};
int sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i];
if (a[i] > s.high) s.high = a[i];
if (a[i] < s.low) s.low = a[i];
}
s.avg = (double)sum / n;
return s;
}
void show(Stat s)
{
printf("인원 %d명\n", s.n);
printf("평균 %.1f 최고 %d 최저 %d\n", s.avg, s.high, s.low);
}
int main(void)
{
int a[100];
int n = read_scores(a, 100);
if (n == 0) return 0;
show(make_stat(a, n));
return 0;
}3 88 92 75
인원 3명 평균 85.0 최고 92 최저 75
마지막 한 줄이 프로그램 전체다
Python 코드의 마지막 줄을 보자.
보여주기(통계내기(점수받기()))
받아서 → 계산해서 → 보여 준다. 프로그램이 하는 일이 한 줄에 그대로 적혀 있다. 3단원 3차시 설계서의 「주 프로그램의 흐름」이 이것이었다.
안쪽부터 실행된다 — 점수받기() 가 먼저 돌아 목록을 만들고, 그것이 통계내기 로 넘어가고, 결과가 보여주기 로 간다.
나누면 무엇이 좋아지나
| 한 덩어리 | 함수로 나눔 | |
|---|---|---|
| 평균이 틀렸을 때 | 코드 전체를 훑는다 | 통계내기 만 본다 |
| 출력 형식을 바꿀 때 | 출력하는 줄을 찾아다닌다 | 보여주기 만 고친다 |
| 입력을 파일에서 받게 바꿀 때 | 앞부분을 뜯어 고친다 | 점수받기 만 갈아 끼운다 |
| 따로 시험하기 | 못 한다 | 함수마다 단위 테스트 (3단원 7차시) |
| 나눠 만들기 | 한 사람만 | 세 사람이 동시에 (3단원 3차시) |
세 번째 줄이 특히 크다. 18차시에서 파일에서 점수를 읽어 오게 바꿀 때, 점수받기 하나만 갈아 끼우면 나머지는 손대지 않아도 된다. 겉모습(정수 목록을 돌려준다)이 같기 때문이다.
어디서 자를지 정하는 기준
3단원 3차시의 기준을 그대로 쓴다.
- 기준 1
한 가지 일만
「받고 계산하고 찍는다」는 셋으로 나눈다. 이름에 「그리고」가 두 번 나오면 다시 쪼갠다.
- 기준 2
이름으로 설명된다
점수받기·통계내기·보여주기. 이름만 보고 하는 일이 짐작되면 잘 나뉜 것이다.
- 기준 3
남의 속을 몰라도
통계내기 는 점수가 어디서 왔는지 모른다. 목록만 받으면 된다.
- 기준 4
두 곳 이상에서 쓰이면
되풀이되는 계산은 따로 떼어 낸다.
여기에 하나를 더한다 — 입력·계산·출력을 섞지 않는다. 14차시에서 계산 함수와 보여 주는 함수를 나눈 이야기가 프로그램 전체 수준에서도 통한다. 계산 함수가 화면을 건드리지 않으면 테스트할 수 있고, 다른 화면에도 붙일 수 있다.
활동
성적 관리 프로그램을 입력·계산·출력 함수로 나눠 구현
약 40분1단계 — 겉모습을 먼저 적는다 (10분)
코드를 쓰기 전에 3단원 3차시의 다섯 칸을 채운다.
| 함수 | 받는 것 | 돌려주는 것 | 하는 일 | 실패하면 |
|---|---|---|---|---|
| 점수받기 | ||||
| 통계내기 | ||||
| 보여주기 |
「실패하면」 칸을 비우지 않는다. 개수를 0으로 넣으면? 숫자 아닌 값이 들어오면?
2단계 — 껍데기부터 만든다 (10분)
3단원 5차시의 순서를 따른다.
- 세 함수를 빈 껍데기로 만들고 정해진 값 하나를 돌려주게 둔다.
- 마지막 줄에서 이어 부르고 한 번 실행해 본다. 결과는 엉터리여도 된다.
- 여기서 실행이 안 되면 이어지는 부분이 틀린 것이다. 잡고 넘어간다.
3단계 — 안쪽부터 채운다 (10분)
남을 부르지 않는 함수부터 채운다. 하나 채울 때마다 실행한다.
| 채운 함수 | 넣은 입력 | 나온 결과 | 손으로 낸 기대 결과 | 같은가 |
|---|---|---|---|---|
4단계 — 기능을 하나 더한다 (10분)
요구 사항을 늘린다.
0 미만 또는 100 초과인 점수는 계산에서 빼고, 제외한 개수를 함께 보여 준다.
- 어느 함수를 고쳐야 하는가? 세 함수 중 몇 개를 건드렸는가?
- 한 덩어리로 썼다면 몇 곳을 고쳐야 했겠는가?
- 3단원 3차시에서
is_valid를 따로 떼어 낸 까닭이 여기서 보이는가?
5단계 — 단위 테스트를 붙인다 (남은 시간)
통계내기 만 따로 시험하는 코드를 만든다. 3단원 7차시의 네 갈래를 쓴다.
| 갈래 | 넣을 값 | 기대 결과 |
|---|---|---|
| 정상값 | [88, 92, 75] |
인원 3, 평균 85.0 |
| 값 하나 | [77] |
|
| 경계값 | [0, 100] |
|
| 빈 목록 | [] |
한 덩어리로 썼다면 이 시험을 할 수 있었을까? 왜 그런지 적는다.
개념 확인 문제
보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.
보여주기(통계내기(점수받기())) 에서 가장 먼저 실행되는 것은?프그02-05
입력을 파일에서 받게 바꿀 때 함수로 나눈 프로그램이 유리한 까닭은?프그02-05
계산하는 함수가 화면을 건드리지 않게 만드는 이점은?프그02-05
C의 read_scores(int a[], int max) 에서 max 를 받는 까닭은?프그02-05
「범위 밖 점수를 뺀다」는 요구가 추가되었을 때 함수로 나눈 프로그램에서 주로 고칠 곳은?프그02-05
함수를 나눠 두면 3단원 7차시의 단위 테스트가 가능해지는 까닭은?프그02-05
더 알아보기
심화파일을 여러 개로 나누기
함수가 늘어나면 파일 하나가 길어진다. 그때는 파일을 나눈다. Python에서는 성적계산.py 를 따로 만들고 import 성적계산 으로 불러 쓴다. C에서는 .c 파일과, 함수 선언만 모은 .h 파일을 짝으로 만든다.
3단원 3차시에서 부품 목록을 만들었을 때 이미 파일 나누기의 밑그림이 그려진 셈이다. 설계서의 부품이 함수가 되고, 관련된 함수들이 모여 파일이 된다. 나누는 기준은 같다 — 한 가지 일, 이름으로 설명, 남의 속을 몰라도.
실무main 은 얇게
잘 나뉜 프로그램의 main 은 짧다. 실제 일은 함수들이 하고 main 은 순서만 적는다. 위 코드의 마지막 한 줄이 그 극단적인 예다.
main 이 길어지고 있다면 그 안에 이름 붙일 만한 일이 숨어 있다는 신호다. 반대로 main 만 읽고 프로그램이 무슨 일을 하는지 알 수 있다면 잘 나뉜 것이다. 남이 쓴 프로그램을 처음 읽을 때도 main 부터 보는 것이 요령이다.
심화가짜 부품으로 먼저 돌려 보기
3단원 5차시와 이 차시 활동 2단계에서 껍데기를 먼저 만들었다. 이 방법이 협업에서 특히 힘을 낸다.
통계내기 가 아직 없어도 정해진 결과 묶음을 돌려주게 만들어 두면, 보여주기 를 맡은 사람은 그것으로 출력 형식을 완성할 수 있다. 셋이 서로를 기다리지 않고 동시에 만드는 것이다.
다만 진짜 부품이 완성되면 임시 코드를 반드시 지운다. 남겨 두면 나중에 왜 이 값이 나오는지 아무도 모르게 된다. 3단원 6차시에서 확인용 출력문을 반드시 지우라고 한 것과 같은 이유다.
이어지는 학습
이 차시를 이해하려면 다음을 먼저 알아야 한다.
- 15차시의 반환값과 유효 범위 — 프로그래밍 프그02-05
교과서에서 찾기
| 교과서 | 해당 위치 | 쪽수 |
|---|---|---|
| 성림출판(Python) | 프로그래밍의 기초 › 05 함수 | 156쪽 |
| 씨마스커뮤니케이션(Python) | 프로그래밍 기초 › 5 함수 | 146쪽 |
| 삼양미디어(Python) | 프로그래밍의 기초 › 04 함수 | 126쪽 |
| 삼양미디어(C) | 프로그래밍의 기초 › 04 함수 | 130쪽 |
| 씨마스(C) | C 프로그래밍의 기초 › 6 함수 | 126쪽 |
| 웅보출판사(C) | 프로그래밍의 기초 › Chapter 05 함수 | 141쪽 |