본문으로 건너뛰기

단원 연습 문제

파이썬 목차반복문제 12개

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개 남음
끝

추적 표로 따라가면 이렇습니다.

줄바뀐 이름값출력
1left5
2조건 left > 0True
3left3
43개 남음
2조건 left > 0True
3left1
41개 남음
2조건 left > 0True
3left-1
4-1개 남음
2조건 left > 0False
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출력
111층
222층
333층
반복 뒤(3번 줄)33

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

반복은 바퀴마다 한 줄로 줄인 추적 표입니다.

줄바뀐 이름값출력
1price1000
2double2000
3·4 (i 0)price2000
3·4 (i 1)price3000
3·4 (i 2)price4000
54000 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

바퀴마다 한 줄로 줄인 추적 표입니다.

바퀴chtotal출력
1'2'22
2'1'33
3'3'66
반복 뒤(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

바퀴마다 한 줄로 줄인 추적 표입니다.

nn > 060 / n >= 30출력
0False계산하지 않음
1True60.0 → True1
2True30.0 → True2

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안쪽 cupcount출력
00·1·21 → 2 → 30 3
10·1·24 → 5 → 61 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번 줄이 처음 어긋나는 줄입니다.

줄바뀐 이름값출력
1total0
2n1
3(없음) 0 == 100False
2n2
3(없음) 0 == 200False
…
40

== 연산자는 같은지 묻고 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의 배수는 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의 배수 합 165

10을 넣으면 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 · 참과 거짓, 비교

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

파이썬 목차로