5단원 '반복'의 여섯 레슨에서 9문제를 내고, 1~4단원에서 3문제를 섞었습니다. 앞 단원 문제가 어느 레슨인지는 정답을 펼치면 보입니다. 출력을 쓰는 문제는 빈칸과 줄바꿈까지 종이에 끝까지 쓴 뒤 정답을 펼치세요. 줄 수를 알려 주지 않는 문제는 마지막 줄까지 다 씁니다. 반복은 추적 표(줄 · 바뀐 이름 · 값 · 출력)를 그리며 따라가면 덜 틀립니다. 막히면 정답 앞의 힌트를 먼저 펼칩니다. 점수는 매기지 않습니다.
한 번에 다 풀 필요는 없습니다. 문제 1~10은 폰으로도 풀 수 있고(약 30분), 끝의 만들어 보기 둘은 컴퓨터에서 직접 돌려 봅니다. 이 단원을 건너뛰어도 되는지 보려면 문제 1 · 2 · 4 · 8 · 9 다섯을 먼저 풀어 보세요(약 15분). 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다. 힌트를 펴고 맞힌 문제나 짐작으로 고른 문제는 틀린 것으로 치고 그 레슨을 봅니다. 모두 맞으면 이 단원 레슨은 건너뛰고, 틀린 문제가 있으면 그 정답 끝의 레슨만 봅니다. 끝의 만들어 보기 둘은 골라서 풉니다.
끝의 두 문제는 프로그램을 직접 만들어 봅니다. 컴퓨터가 있으면 저장해 돌려 맞춰 보고, 폰으로만 본다면 문제에 적힌 값으로 내 코드를 한 줄씩 따라가 나와야 할 화면과 맞춰 봅니다. 실행 결과는 모두 파이썬 3.15로 돌린 것입니다.
문제 1
쿠키 5개를 손님마다 2개씩 나눠 주며 남은 수를 찍습니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.
left = 5
while left > 0:
left = left - 2
print(f'{left}개 남음')
print('끝')
힌트
2번 줄의 조건을 언제 보는지, 추적 표로 한 줄씩 따라가 보세요.
정답
모두 4줄입니다.
3개 남음
1개 남음
-1개 남음
끝추적 표로 따라가면 이렇습니다.
| 줄 | 바뀐 이름 | 값 | 출력 |
|---|---|---|---|
| 1 | left | 5 | |
| 2 | 조건 left > 0 | True | |
| 3 | left | 3 | |
| 4 | 3개 남음 | ||
| 2 | 조건 left > 0 | True | |
| 3 | left | 1 | |
| 4 | 1개 남음 | ||
| 2 | 조건 left > 0 | True | |
| 3 | left | -1 | |
| 4 | -1개 남음 | ||
| 2 | 조건 left > 0 | False | |
| 5 | 끝 |
셋째 바퀴의 3번 줄에서 left가 -1에 붙어 조건이 거짓이 되어도, 그 바퀴는 4번 줄까지 마저 실행해 -1개 남음을 찍습니다.
흔한 오답은 -1개 남음을 빼는 것입니다. left가 0보다 작아지는 순간 반복이 멈춘다고 본 것입니다(조건을 늘 지켜본다는 생각). 조건은 바퀴를 시작할 때(2번 줄)만 봅니다(규칙 4).
다시 볼 레슨: while과 추적 표
문제 2
엘리베이터가 층마다 안내를 찍습니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.
for floor in range(1, 4):
print(f'{floor}층')
print(floor)
힌트
range(1, 4)가 내주는 수를 먼저 적고, 반복이 끝난 뒤 floor가 어느 값에 붙어 있는지 보세요.
정답
모두 4줄입니다.
1층
2층
3층
3바퀴마다 한 줄로 줄인 추적 표입니다.
| 바퀴 | floor | 출력 |
|---|---|---|
| 1 | 1 | 1층 |
| 2 | 2 | 2층 |
| 3 | 3 | 3층 |
| 반복 뒤(3번 줄) | 3 | 3 |
range(1, 4)는 1, 2, 3을 차례로 내주고 끝 수 4는 내주지 않습니다. 꺼낸 수에 floor를 붙일 때마다 2번 줄이 찍습니다. 반복이 끝나도 floor는 마지막에 붙은 3에 그대로 붙어 있어 3번 줄이 3을 찍습니다.
흔한 오답은 4층까지 쓰는 것입니다. 끝 수도 든다고 본 것입니다(끝도 든다는 생각). 마지막 줄을 4로 쓰면 반복이 끝나면 이름이 끝 수에 붙는다고 본 것입니다.
다시 볼 레슨: for와 range
문제 3
커피 값을 세 번 1,000원씩 올립니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
price = 1000
double = price * 2
for i in range(3):
price = price + 1000
print(price, double)
힌트
2번 줄이 실행되는 그때 price가 어느 값에 붙어 있는지, 반복이 몇 바퀴인지 보세요.
정답
4000 2000반복은 바퀴마다 한 줄로 줄인 추적 표입니다.
| 줄 | 바뀐 이름 | 값 | 출력 |
|---|---|---|---|
| 1 | price | 1000 | |
| 2 | double | 2000 | |
| 3·4 (i 0) | price | 2000 | |
| 3·4 (i 1) | price | 3000 | |
| 3·4 (i 2) | price | 4000 | |
| 5 | 4000 2000 |
2번 줄이 실행되는 그때 price가 1000이라 1000 * 2를 계산한 값 2000에 double이 붙습니다. range(3)은 0, 1, 2 세 수를 내줘 세 바퀴를 돌고, 그동안 double은 다시 계산되지 않습니다.
흔한 오답은 4000 8000입니다. double이 price * 2라는 식을 저장해 두었다가 찍을 때 다시 계산한다고 본 것입니다(식이 저장된다는 생각). 5000 2000으로 쓰면 range(3)이 네 바퀴를 돈다고 본 것입니다(끝도 든다는 생각).
다시 볼 레슨: 변수: 값에 이름 붙이기 · for와 range
문제 4
오늘 주문 수량을 커피·라테·쿠키 차례로 '213'이라는 글자로 적었습니다. 수량을 더할 때마다 지금까지의 합을 찍고, 다 더한 뒤에는 합계를 한 번 더 찍으려 합니다. 이렇게 나와야 합니다.
2
3
6
합계 6
아래 줄 ㉠~㉥ 가운데 다섯 줄을 뼈대 코드의 주석 아래에 놓으세요. 한 줄은 쓰지 않습니다. 들여쓰기는 지웠습니다. 줄마다 들여쓰기 칸 수(0 또는 4)도 함께 쓰세요.
㉠ total = total + int(ch)
㉡ print('합계', total)
㉢ total = int(ch)
㉣ for ch in counts:
㉤ print(total)
㉥ total = 0
counts = '213'
# 1. 합을 0으로
# 2. 하나씩 꺼내 더하기
# 3. 끝나고 쓰기
힌트
나와야 할 화면에서 바퀴마다 찍히는 줄과 한 번만 찍히는 줄을 먼저 가르세요.
놓은 뒤 물음
㉤의 들여쓰기 칸 수를 그렇게 정한 까닭은 무엇일까요?
- ① 들여쓰기는 보기 좋게 맞출 뿐이라, 몇 칸에 두어도 결과가 같기 때문
- ② 덩어리 안에 두어도, 반복이 다 끝난 뒤 지금까지의 합을 한 번 찍기 때문
- ③
for덩어리 안에 두어야, 바퀴마다 지금까지의 합을 한 번씩 찍기 때문
정답
㉥(0) ㉣(0) ㉠(4) ㉤(4) ㉡(0) 차례이고, 까닭은 ③입니다. 쓰지 않는 줄은 ㉢입니다.
counts = '213'
# 1. 합을 0으로
total = 0
# 2. 하나씩 꺼내 더하기
for ch in counts:
total = total + int(ch)
print(total)
# 3. 끝나고 쓰기
print('합계', total)2
3
6
합계 6바퀴마다 한 줄로 줄인 추적 표입니다.
| 바퀴 | ch | total | 출력 |
|---|---|---|---|
| 1 | '2' | 2 | 2 |
| 2 | '1' | 3 | 3 |
| 3 | '3' | 6 | 6 |
| 반복 뒤(9번 줄) | 6 | 합계 6 |
6·7번 줄은 4칸이라 for 덩어리에 들어 바퀴마다 실행되고, 9번 줄은 들여 쓰지 않아 반복이 끝난 뒤 한 번 실행됩니다(규칙 4).
서로 바꿔도 되는 줄은 없습니다. ㉢을 ㉠ 자리에 쓰면 total이 바퀴마다 그 수량에만 다시 붙어 2·1·3·합계 3이 찍힙니다. 이름이 total이라 알아서 합이 된다고 본 것입니다(이름이 뜻을 정한다는 생각).
- ① 들여쓰기를 보기 좋게 맞추는 것으로 봤습니다(들여쓰기는 꾸밈이라는 생각). ㉤을 0칸에 두면 반복 밖이라
6을 한 번만 찍어2·3이 빠집니다. - ② 덩어리 안의
print도 반복이 끝난 뒤 한 번만 실행된다고 봤습니다(들여쓰기는 꾸밈이라는 생각). 4칸에 둔 줄은 덩어리에 들어 바퀴마다 실행됩니다.
다시 볼 레슨: 합 모으기와 세기 · for와 range
문제 5
앞 문제처럼 주문 수량 '213'을 더하는 다른 코드입니다. 이 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.
total = 0
print('더하기 시작')
for ch in '213':
total = total + ch
print(total)
- ①
더하기 시작을 찍은 뒤, 첫 바퀴의 4번 줄에서TypeError로 멈춘다 - ② 아무것도 찍지 않고, 실행하기 전에 4번 줄의
TypeError로 멈춘다 - ③
더하기 시작을 찍고, 세 바퀴를 다 돈 뒤 5번 줄이6을 찍는다 - ④
더하기 시작을 찍고, 세 바퀴를 다 돈 뒤 5번 줄이213을 찍는다
힌트
4번 줄의 + 양쪽에 오는 값의 종류를 보세요.
정답
① — 실행 결과는 이렇습니다.
더하기 시작Traceback (most recent call last): File "main.py", line 4, in <module> total = total + ch ~~~~~~^~~~TypeError: unsupported operand type(s) for +: 'int' and 'str'2번 줄이 더하기 시작을 찍고, 첫 바퀴에서 total은 수 0, ch는 글자 '2'입니다. 수와 글자는 +로 더할 수도 이을 수도 없어 4번 줄에서 멈춥니다. 값의 종류가 맞지 않는 것은 그 줄을 실행할 때 알게 되는 실행 중 오류라, 앞에서 찍은 줄은 남습니다. 맨 아래 줄은 '+는 int와 str 사이에 쓸 수 없다'는 뜻입니다.
- ② 실행 중 오류를 문법 오류처럼 봤습니다. 종류가 맞지 않는 것은 실행해 봐야 알아, 4번 줄 앞의 줄은 실행됩니다.
- ③ 글자 '2'도 수처럼 더해진다고 봤습니다(문자열과 수를 가리지 않는 생각). 수로 더하려면
int(ch)처럼 수를 만든 뒤 더합니다. - ④ 수에 글자를 이으면 글자로 맞춰진다고 봤습니다. 파이썬은 글자와 수 사이에서 종류를 저절로 맞춰 주지 않습니다. 글자를 이으려면 total을 빈 문자열
''에 붙여 시작합니다.
다시 볼 레슨: 수와 글자 · 입력은 늘 글자 · 오류 메시지 읽기 · 작은 계산기 만들기
문제 6
다음 코드가 하는 일로 알맞은 것을 고르세요.
word = 'banana'
count = 0
for ch in word:
if ch == 'a':
count = count + 1
print(count)
- ① word의 글자를 하나씩 세어 글자 수를 찍는다
- ② word에 든 'a'가 몇 개인지 세어 찍는다
- ③ word에서 'a'를 찾으면 거기서 멈추고, 찾았는지를 찍는다
힌트
5번 줄은 어느 덩어리 안에 있는지, 반복을 멈추는 줄이 있는지 보세요.
정답
② — 세기 틀입니다. 글자를 하나씩 꺼내 'a'일 때만 count에 1을 더하고, 반복이 끝난 뒤 한 번 찍습니다.
3- ① 5번 줄이
if덩어리 안이라는 것을 놓쳤습니다(들여쓰기는 꾸밈이라는 생각). 그러면 6을 찍습니다. - ③ 찾으면 멈추기 틀과 헷갈렸습니다. 이 코드에는 반복을 끝내는
break가 없어 여섯 글자를 다 봅니다.
다시 볼 레슨: 합 모으기와 세기 · break와 continue
문제 7
사탕 60개를 n명이 똑같이 나눌 때 한 사람 몫이 30개 이상인 n을 찾습니다. 무엇이 찍힐까요? 마지막 줄까지 쓰고, 오류가 난다고 보면 찍히는 줄 다음에 오류 이름을 쓰세요.
for n in range(3):
if n > 0 and 60 / n >= 30:
print(n)
힌트
n이 0인 첫 바퀴에서 and의 왼쪽이 무엇으로 접히는지 보세요.
정답
모두 2줄입니다.
1
2바퀴마다 한 줄로 줄인 추적 표입니다.
| n | n > 0 | 60 / n >= 30 | 출력 |
|---|---|---|---|
| 0 | False | 계산하지 않음 | |
| 1 | True | 60.0 → True | 1 |
| 2 | True | 30.0 → True | 2 |
n이 0인 첫 바퀴는 0 > 0이 False라 and의 답이 이미 False입니다. 오른쪽 60 / 0은 계산하지 않아 오류가 나지 않습니다.
흔한 오답은 첫 바퀴에서 ZeroDivisionError로 멈춘다고 쓰는 것입니다. and가 늘 양쪽을 다 계산한다고 본 것입니다(양쪽을 다 계산한다는 생각). 두 비교의 차례를 바꿔 60 / n >= 30을 왼쪽에 두었다면 그 자리에서 ZeroDivisionError로 멈춥니다.
다시 볼 레슨: and·or·not · for와 range
문제 8
이틀 동안 하루에 커피 세 잔씩 내리며 잔 수를 셉니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.
count = 0
for day in range(2):
for cup in range(3):
count = count + 1
print(day, count)
힌트
count를 0에 붙이는 줄이 반복 안에 있는지 밖에 있는지, range(2)가 내주는 수를 보세요.
정답
0 3
1 6바깥 바퀴마다 한 줄로 줄인 추적 표입니다.
| day | 안쪽 cup | count | 출력 |
|---|---|---|---|
| 0 | 0·1·2 | 1 → 2 → 3 | 0 3 |
| 1 | 0·1·2 | 4 → 5 → 6 | 1 6 |
range(2)가 0과 1을 내줘 바깥 반복은 두 바퀴입니다. 바깥 한 바퀴마다 안쪽 반복이 처음부터 세 바퀴를 다 돌아 count에 1씩 세 번 더합니다. count는 1번 줄에서 한 번만 0에 붙어, 둘째 바퀴에도 3에서 이어 6이 됩니다. 5번 줄은 4칸 들여 써서 바깥 바퀴마다 한 번 찍습니다.
흔한 오답은 둘째 줄의 1 3입니다. 안쪽 반복이 처음부터 다시 돌 때 count도 0부터 다시 센다고 본 것입니다. 처음부터 다시 도는 것은 안쪽 range(3)이 내주는 수이고, count는 반복 밖에서 붙인 그대로 이어집니다. day를 1·2로 쓰면 range(2)가 1부터 센다고 본 것입니다.
다시 볼 레슨: 반복 안의 반복 · for와 range
문제 9
하고 싶은 일마다 쓸 낱말이나 값을 하나씩 쓰세요. 넷 다 쓴 뒤 정답을 펼치세요.
- (가) 반복을 그 자리에서 끝낸다
- (나) 이번 바퀴의 남은 줄만 건너뛰고 다음 바퀴로 간다
- (다)
while조건 자리에 두어 늘 참이게 하는 값(그래서 조건으로는 끝나지 않는다) - (라) 아무것도 치지 않고 Enter를 쳤을 때
input()이 돌려주는 값
힌트
둘은 반복 안에서만 쓰는 낱말, 하나는 첫 글자가 대문자인 값, 하나는 따옴표로 쓰는 값입니다.
정답
받는 답: (가) break · (나) continue · (다) True · (라) ''(빈 문자열)
- 같은 답으로 치는 꼴: (라)를 큰따옴표로 쓴
"". - 틀리는 꼴
continue— (가)에,break— (나)에: 둘이 뒤바뀐 것입니다. 반복을 끝내는 것은break, 이번 바퀴만 건너뛰는 것은continue입니다. - 틀리는 꼴
true— (다)에: 소문자는 만든 적 없는 이름이라NameError입니다. - 틀리는 꼴
0— (라)에: 빈 줄은 빈 문자열이고,int('')는 0이 아니라ValueError로 멈춥니다.
다시 볼 레슨: break와 continue · 작은 계산기 만들기
문제 10
책 세 권의 쪽수(100쪽·200쪽·300쪽)를 더하려 합니다. 600이 찍혀야 하는데 아래처럼 0이 찍혔습니다. 몇 번 줄의 무엇을 고쳐야 할까요? 고친 줄을 쓰세요.
total = 0
for n in range(1, 4):
total == total + n * 100
print(total)
0힌트
3번 줄을 추적 표에 적으면 바뀐 이름 칸에 무엇이 들어가는지 보세요.
정답
3번 줄의 == 기호를 =로 고칩니다.
total = 0
for n in range(1, 4):
total = total + n * 100
print(total)600고치기 전 코드를 추적 표로 따라가면, 3번 줄이 처음 어긋나는 줄입니다.
| 줄 | 바뀐 이름 | 값 | 출력 |
|---|---|---|---|
| 1 | total | 0 | |
| 2 | n | 1 | |
| 3 | (없음) 0 == 100 | False | |
| 2 | n | 2 | |
| 3 | (없음) 0 == 200 | False | |
| … | |||
| 4 | 0 |
== 연산자는 같은지 묻고 False를 만들 뿐 이름을 붙이지 않습니다. 그래서 total은 1번 줄의 0에 그대로 붙어 있었습니다. 이름을 새 값에 다시 붙이는 것은 =입니다(규칙 2).
- 다르게 고쳐도 되는 곳:
total += n * 100도 600입니다. - 흔한 오답은
total = n * 100으로 고치는 것입니다. 바퀴마다 total을 그 책의 쪽수에 다시 붙이기만 해서 마지막 300이 찍힙니다(이름이 뜻을 정한다는 생각).
문제 11 (만들어 보기)
1부터 끝 수까지의 3의 배수만 더하는 계산기를 만들어 봅니다. 끝 수를 물어 1부터 끝 수까지(끝 수도 넣어서) 3의 배수의 합을 찍습니다. 30을 넣으면 이렇게 나와야 합니다.
끝 수: 30
3의 배수 합 165
10을 넣으면 이렇게 나와야 합니다.
끝 수: 10
3의 배수 합 18
아래 뼈대에서 1번 줄은 그대로 두고, 주석 셋 아래를 채우세요. 다 쓰면 둘째 값으로도 따라가 봅니다.
last = int(input('끝 수: '))
# 1. 합을 0으로
# 2. 하나씩 꺼내 맞으면 더하기
# 3. 끝나고 쓰기넣는 값30
처음 펼 때 약 6MB를 받습니다.
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
견줄 시험 값
input()마다 위에서부터 한 줄씩 들어갑니다.
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 넣은 값 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.
힌트
3의 배수는 3으로 나눈 나머지가 0입니다. 끝 수 30이 range가 내주는 수에 드는지 보세요.
정답
모범 답입니다. 30을 넣은 결과입니다.
last = int(input('끝 수: '))
# 1. 합을 0으로
total = 0
# 2. 하나씩 꺼내 맞으면 더하기
for n in range(1, last + 1):
if n % 3 == 0:
total = total + n
# 3. 끝나고 쓰기
print('3의 배수 합', total)넣는 값30끝 수: 30
3의 배수 합 16510을 넣으면 n이 3, 6, 9일 때만 더해 total이 3 → 9 → 18이 됩니다.
- 다르게 써도 되는 곳: 7번 줄을
total += n으로 써도 되고,while로 n을 1부터 last까지 늘려 가며 써도 됩니다. - 찍은 화면이 위와 같고 10에서도
3의 배수 합 18이 나오면 맞습니다. - 흔한 오답은
range(1, last)입니다. 끝 수 30이 빠져 135가 찍힙니다. 10에서는 10이 3의 배수가 아니라 18로 같아서, 30을 넣어 봐야 드러납니다.total = n으로 쓰면 마지막 3의 배수 30만 남고(이름이 뜻을 정한다는 생각),total + 1로 쓰면 합이 아니라 개수 10이 찍힙니다. 9번 줄을if안에 들여 쓰면 더할 때마다,for안에 두면 바퀴마다 찍혀 여러 줄이 나옵니다.
다시 볼 레슨: 합 모으기와 세기 · for와 range
문제 12 (만들어 보기)
이번에는 빈 데서 씁니다. 도어락이 비밀번호를 세 번까지 묻습니다. 1234를 치면 열렸습니다를 찍고 더 묻지 않으며, 세 번 모두 틀리면 잠겼습니다를 찍는 프로그램을 쓰세요. 물을 때 쓰는 글은 '비밀번호: '입니다. 0000과 1234를 차례로 넣으면 이렇게 나와야 합니다.
비밀번호: 0000
비밀번호: 1234
열렸습니다
7·8·1234를 넣으면 이렇게 나와야 합니다.
비밀번호: 7
비밀번호: 8
비밀번호: 1234
열렸습니다
다 쓰면 둘째 값으로도 따라가 보고, 1·2·3도 넣어 봅니다. 세 번 묻고 잠겼습니다가 나와야 합니다.
힌트
하위 목표 셋(1. 깃발 내리기 · 2. 하나씩 보며 찾으면 올리고 멈추기 · 3. 깃발 보고 쓰기)의 주석을 먼저 쓰고, 2번 아래에서 세 번 묻습니다.
정답
모범 답입니다. 0000과 1234를 넣은 결과입니다. 1번 줄이 '1. 깃발 내리기', 2~6번 줄이 '2. 하나씩 보며 찾으면 올리고 멈추기', 7~10번 줄이 '3. 깃발 보고 쓰기'입니다.
ok = False
for i in range(3):
text = input('비밀번호: ')
if text == '1234':
ok = True
break
if ok:
print('열렸습니다')
else:
print('잠겼습니다')넣는 값00001234비밀번호: 0000
비밀번호: 1234
열렸습니다1·2·3을 넣으면 break를 만나지 않고 세 바퀴를 다 돌아 ok가 처음의 False 그대로라 잠겼습니다입니다. 7·8·1234면 셋째 바퀴에서 깃발을 올리고 멈춥니다.
- 다르게 써도 되는 곳: 묻은 횟수를 세는 이름을 두고
while로 세 번까지 물어도 됩니다. 1234를 맞힌 줄에서 바로열렸습니다를 찍지 않고 깃발로 미루는 까닭은, 세 번 다 틀렸는지는 반복이 끝나야 알기 때문입니다. - 찍은 화면이 위와 같고 1·2·3과 7·8·1234에서도 맞으면 맞습니다.
- 흔한 오답은
break를 빠뜨리는 것입니다. 1234를 맞힌 뒤에도 세 번째로 비밀번호를 묻습니다.range(1, 3)으로 쓰면 두 번만 물어 7·8·1234에서 잠깁니다(끝도 든다는 생각).text == 1234처럼 따옴표 없이 견주면 1234를 쳐도 열리지 않습니다.input()이 돌려준 글자와 수는 같을 수 없습니다(문자열과 수를 가리지 않는 생각).잠겼습니다를 반복 안의else에서 찍으면 틀릴 때마다 찍힙니다.
다시 볼 레슨: break와 continue · for와 range · 참과 거짓, 비교