본문으로 건너뛰기

단원 연습 문제

파이썬 목차오류와 예외문제 12개

9단원 '오류와 예외'의 세 레슨에서 일곱 문제를 내고, 앞 단원(반복과 패턴 · 딕셔너리 · 함수)에서 다섯 문제를 섞었습니다. 눈으로 코드를 따라가 무엇이 찍히는지 쓰거나, 빈칸을 채우고, 잘못된 줄을 고치거나, 짧은 프로그램을 직접 만듭니다.

한 번에 다 풀 필요는 없습니다. 문제 1~10은 폰으로도 풀 수 있고(약 12분), 끝의 만들어 보기 둘은 컴퓨터에서 직접 돌려 봅니다. 이 단원을 건너뛰어도 되는지 보려면 문제 4·7·10을 먼저 풀어 보세요(약 4분). 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다. 세 문제가 모두 맞으면 10단원 첫 레슨 글과 리스트 사이: split·join으로 넘어가고, 하나라도 틀리면 정답 끝에 적힌 '다시 볼 레슨'으로 돌아갑니다.

끝의 두 문제는 프로그램을 직접 만들어 봅니다. 아래 코드 칸에서 바로 고쳐 돌려 볼 수 있고, 내 컴퓨터에서 돌려 보는 길은 내 컴퓨터에서 돌려 보기에 있습니다. 실행 결과는 모두 파이썬 3.15로 돌린 것입니다.

문제 1

문자열 '15'를 정수로 바꾸어 5를 더하는 코드입니다. 무엇이 찍힐까요? 두 줄을 쓰세요.

text = '15'
try:
    n = int(text)
    print(n + 5)
except ValueError:
    print('숫자 아님')
print('끝')
힌트

int('15')는 오류 없이 정수 15를 돌려줍니다. try 안에서 오류가 나지 않았을 때 except 블록과 바깥의 마지막 줄이 어떻게 되는지 보세요.

정답
실행 결과
20
끝
  • 3~4번 줄: int('15')가 정수 15가 되어 15 + 5인 20을 찍습니다.
  • 5~6번 줄: try 안에서 오류가 나지 않았으므로 except ValueError: 블록은 통째로 건너뜁니다.
  • 7번 줄: 바깥의 print('끝')이 이어서 실행됩니다.

흔한 오답은 20 다음에 숫자 아님도 함께 적는 것입니다. except 블록도 위에서 아래로 늘 실행된다고 본 것입니다. except 블록은 try 안에서 해당 오류가 났을 때만 실행됩니다.

다시 볼 레슨: try와 except

문제 2

숫자가 아닌 '다섯'을 정수로 바꾸려 합니다. 무엇이 찍힐까요? 두 줄을 쓰세요.

text = '다섯'
try:
    print('변환 시작')
    n = int(text)
    print('성공:', n)
except ValueError:
    print('숫자로 적어 주세요')
힌트

3번 줄과 5번 줄 가운데 어느 줄이 오류가 나는 4번 줄보다 앞에 있는지, 4번 줄에서 오류가 난 순간 어디로 이동하는지 보세요.

정답
실행 결과
변환 시작
숫자로 적어 주세요
  • 3번 줄: 아직 오류가 나기 전이므로 '변환 시작'이 먼저 찍힙니다(규칙 1).
  • 4번 줄: int('다섯')에서 ValueError가 나는 순간, try 안의 남은 5번 줄 print('성공:', n)은 건너뛰고 바로 6번 줄 except ValueError:로 넘어갑니다.
  • 7번 줄: '숫자로 적어 주세요'를 찍고 끝납니다.

흔한 오답은 '변환 시작' 없이 '숫자로 적어 주세요' 한 줄만 쓰는 것입니다. try 안에서 나중에 오류가 나면 앞줄도 취소된다고 본 것입니다. 이미 실행된 3번 줄의 출력은 사라지지 않습니다.

다시 볼 레슨: try와 except

문제 3

세 물건 값 [1500, 2000, 2500]의 합 6000을 구하려 한 코드인데 2500이 나왔습니다. 바퀴마다 찍은 점검 줄을 보고 몇 번째 바퀴에서 예측(1500, 3500, 6000)과 실제가 처음 갈리는지 찾고, 잘못된 줄을 고쳐 쓰세요.

prices = [1500, 2000, 2500]
total = 0
for p in prices:
    total = p
    print('점검:', p, total)
print(total)
실행 결과
점검: 1500 1500
점검: 2000 2000
점검: 2500 2500
2500
힌트

첫 바퀴에서는 0 + 1500과 덮어쓴 1500이 우연히 같습니다. 두 번째 바퀴(p = 2000)에서 기대한 합 3500과 실제 찍힌 값을 견주어 보세요.

정답

두 번째 바퀴(p = 2000)에서 예측(3500)과 실제(2000)가 처음 갈립니다. 4번 줄 total = p를 total = total + p로 고치고 점검용 5번 줄을 지웁니다.

prices = [1500, 2000, 2500]
total = 0
for p in prices:
    total = total + p
print(total)
실행 결과
6000

4번 줄 total = p는 앞 바퀴까지 모은 total에 p를 더하지 않고 새 p에 이름을 다시 붙이기만 했습니다(규칙 3).

다시 볼 레슨: 값을 찍어 보며 고치기 · 합 모으기와 세기

문제 4

다음 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.

d = 0
try:
    print('나누기 시작')
    q = 100 // d
    print('몫:', q)
except ValueError:
    print('잘못된 값입니다')
  • ① '나누기 시작'이 찍힌 뒤 4번 줄에서 ZeroDivisionError로 멈춘다
  • ② '나누기 시작'과 '잘못된 값입니다'가 차례로 찍히고 끝난다
  • ③ 아무것도 찍지 않고 바로 ZeroDivisionError로 멈춘다
  • ④ '나누기 시작', '몫: 0', '잘못된 값입니다'가 차례로 찍힌다
힌트

4번 줄 100 // 0에서 나는 오류 이름과 6번 줄 except 뒤에 적힌 오류 이름이 같은지 비교해 보세요.

정답

① — 실행 결과는 이렇습니다.

실행 결과
나누기 시작Traceback (most recent call last):  File "main.py", line 4, in <module>    q = 100 // d        ~~~~^^~~ZeroDivisionError: division by zero
  • ① (정답): 3번 줄에서 '나누기 시작'을 찍은 뒤 4번 줄 100 // 0에서 ZeroDivisionError가 납니다. 6번 줄은 ValueError만 잡으므로 이 오류는 잡히지 않고 멈춥니다.
  • ② try로 감싸면 모든 오류를 다 잡아 준다고 봤습니다. except 오류이름:은 지정한 이름과 일치하는 오류만 잡습니다.
  • ③ 실행하기 전에 ZeroDivisionError를 미리 알아챈다고 봤습니다. 실행 중 오류는 그 줄에 닿을 때 나므로 앞선 3번 줄은 실행됩니다(규칙 1).
  • ④ 오류가 나도 try 안의 남은 줄이 마저 돈다고 봤습니다. 오류가 나는 순간 5번 줄은 건너뜁니다.

다시 볼 레슨: try와 except · 오류 메시지 읽기

문제 5

과일 재고 딕셔너리에서 숫자로 적힌 재고만 골라 합을 구합니다. 무엇이 찍힐까요? 두 줄을 쓰세요.

stock = {
    '사과': '10',
    '배': '품절',
    '감': '5',
}
total = 0
for k in stock:
    try:
        total += int(stock[k])
    except ValueError:
        print('제외:', k)
print('재고 합:', total)
힌트

for k in stock:은 키 '사과', '배', '감'을 차례로 꺼냅니다. stock['배']가 '품절'일 때 9번 줄 int('품절')에서 무슨 일이 일어나는지 보세요.

정답
실행 결과
제외: 배
재고 합: 15
  • 첫 바퀴(k = '사과'): int('10')이 10이 되어 total이 10이 됩니다.
  • 두 번째 바퀴(k = '배'): int('품절')에서 ValueError가 나 덧셈이 일어나지 않고 except ValueError:로 가서 '제외: 배'를 찍습니다.
  • 세 번째 바퀴(k = '감'): int('5')가 5가 되어 total이 15가 됩니다.

흔한 오답은 '제외: 품절'로 쓰는 것입니다. k에는 값이 아니라 키 '배'가 들어 있습니다.

다시 볼 레슨: try와 except · 딕셔너리 돌기

문제 6

다음 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.

text = '열'
try:
    n = int(text)
except ValueError:
    print(n)
  • ① 열이 찍히고 끝난다
  • ② 0이 찍히고 끝난다
  • ③ 5번 줄에서 NameError로 멈춘다
힌트

3번 줄 n = int(text)는 오른쪽 int(text)를 먼저 계산한 뒤 그 결과에 이름 n을 붙입니다(규칙 3). 오른쪽을 계산하다가 오류가 나면 이름 n이 생겼을지 생각해 보세요.

정답

③ — 실행 결과는 이렇습니다.

실행 결과
Traceback (most recent call last):  File "main.py", line 3, in <module>    n = int(text)ValueError: invalid literal for int() with base 10: '열' During handling of the above exception, another exception occurred: Traceback (most recent call last):  File "main.py", line 5, in <module>    print(n)          ^NameError: name 'n' is not defined

3번 줄 오른쪽 int('열')에서 ValueError가 나는 순간 대입이 취소되어 이름 n은 만들어지지 않습니다(규칙 3). 그래서 5번 줄이 없는 이름 n을 읽으려다 NameError로 멈춥니다.

  • ① 변환 전의 '열'이 n에 들어간다고 봤습니다. '열'이 붙어 있는 이름은 text입니다.
  • ② 오류가 나면 n에 기본값 0이 저절로 들어간다고 봤습니다. 파이썬은 기본값을 알아서 넣지 않습니다.

다시 볼 레슨: try와 except · 변수: 값에 이름 붙이기

문제 7

1부터 3 사이의 번호를 받을 때까지 다시 묻는 코드입니다. '가', '0', '2'를 차례로 넣으면 무엇이 찍힐까요? 여섯 줄을 쓰세요.

while True:
    raw = input('번호: ')
    try:
        n = int(raw)
    except ValueError:
        print('숫자 아님')
        continue
    if 1 <= n <= 3:
        break
    print('범위 밖')
print('선택:', n)넣는 값가02
힌트

input('번호: ') 줄은 프롬프트와 입력한 값을 한 줄(번호: 가)로 찍습니다. 세 입력이 각각 첫째 관문(try / except)과 둘째 관문(if 1 <= n <= 3:) 가운데 어디에서 걸리는지 따라가 보세요.

정답
실행 결과
번호: 가
숫자 아님
번호: 0
범위 밖
번호: 2
선택: 2
  • 첫 바퀴('가'): int('가')에서 ValueError가 나 '숫자 아님'을 찍고 continue로 돌아갑니다.
  • 두 번째 바퀴('0'): int('0')은 통과하지만 1 <= 0 <= 3이 False라 break를 건너뛰고 '범위 밖'을 찍습니다.
  • 세 번째 바퀴('2'): 두 관문을 모두 통과해 break로 나가 '선택: 2'를 찍습니다.

흔한 오답은 첫 바퀴에 '숫자 아님' 다음에 '범위 밖'도 함께 적는 것입니다. except 안의 continue가 8~10번 줄을 건너뛰게 한다는 점을 놓친 것입니다.

다시 볼 레슨: 맞는 값이 올 때까지 다시 묻기 · break와 continue

문제 8

점수 [70, 85, 90]에서 80점 이상인 과목 수(2)를 세려는데 1이 찍혔습니다. 점검 출력을 보고 몇 번째 바퀴에서 예측(0, 1, 2)과 실제가 처음 갈리는지 찾고, 어떻게 고쳐야 할지 쓰세요.

scores = [70, 85, 90]
for s in scores:
    count = 0
    if s >= 80:
        count = count + 1
    print('점검:', s, count)
print(count)
실행 결과
점검: 70 0
점검: 85 1
점검: 90 1
1
힌트

두 번째 바퀴(s = 85)가 끝날 때 count는 1이었습니다. 세 번째 바퀴(s = 90)에 들어가자마자 3번 줄이 count를 무엇으로 바꾸는지 보세요.

정답

세 번째 바퀴(s = 90)에서 예측(2)과 실제(1)가 처음 갈립니다. 3번 줄 count = 0을 for 반복문 위로 옮기고 점검용 6번 줄을 지웁니다.

scores = [70, 85, 90]
count = 0
for s in scores:
    if s >= 80:
        count = count + 1
print(count)
실행 결과
2

count = 0이 반복문 안에 있으면 바퀴마다 count를 다시 0에 붙여 앞 바퀴까지 세어 둔 개수가 사라집니다.

다시 볼 레슨: 값을 찍어 보며 고치기 · 세기: 메뉴별로 모으기

문제 9

1부터 5 사이의 숫자를 받을 때까지 다시 묻는 코드입니다. 빈칸 (가)와 (나)에 들어갈 키워드를 차례로 쓰세요.

while True:
    raw = input('1~5: ')
    try:
        n = int(raw)
    except ValueError:
        print('숫자만 됩니다')
        ____(가)____
    if 1 <= n <= 5:
        ____(나)____
    print('1~5만 됩니다')
힌트

(가)는 변환이 실패했을 때 아래 범위 검사를 건너뛰고 다음 바퀴로 돌아가는 키워드이고, (나)는 범위까지 맞았을 때 반복을 끝내는 키워드입니다.

정답
  • (가): continue
  • (나): break
while True:
    raw = input('1~5: ')
    try:
        n = int(raw)
    except ValueError:
        print('숫자만 됩니다')
        continue
    if 1 <= n <= 5:
        break
    print('1~5만 됩니다')
print('통과:', n)넣는 값열94
실행 결과
1~5: 열
숫자만 됩니다
1~5: 9
1~5만 됩니다
1~5: 4
통과: 4

흔한 오답은 (가)와 (나)를 거꾸로 쓰는 것입니다. except 안에 break를 쓰면 잘못된 글자를 넣었을 때 다시 묻지 않고 반복이 끝나 버립니다.

다시 볼 레슨: 맞는 값이 올 때까지 다시 묻기 · break와 continue

문제 10

문자열로 적힌 가격에 배달비 3,000원을 더해 돌려주는 함수입니다. '5000'을 넘겼으니 8000이 찍혀야 하는데 '숫자 아님'이 찍혔습니다. 잘못된 두 곳(4번 줄과 5번 줄)을 어떻게 고쳐야 할까요?

def total_pay(raw):
    try:
        price = int(raw)
        return pric + 3000
    except:
        return '숫자 아님'


print(total_pay('5000'))
실행 결과
숫자 아님
힌트

int('5000')은 성공했습니다. 그런데 4번 줄에서 더해 주는 변수 이름 철자를 자세히 보고, 왜 파이썬이 NameError를 내지 않고 6번 줄로 갔는지 5번 줄을 살펴보세요.

정답

4번 줄의 오타 pric을 price로 고치고, 5번 줄의 맨몸 except:를 except ValueError:로 고칩니다.

def total_pay(raw):
    try:
        price = int(raw)
        return price + 3000
    except ValueError:
        return '숫자 아님'


print(total_pay('5000'))
실행 결과
8000

고치기 전에는 4번 줄에서 price 대신 pric이라고 잘못 적어 NameError가 났는데, 5번 줄이 오류 이름 없는 except:라 NameError까지 삼켜 버리고 '숫자 아님'을 돌려주었습니다. except ValueError:처럼 잡을 오류 이름을 밝혀 적어야 내 코드의 오타가 숨지 않습니다.

다시 볼 레슨: try와 except · 돌려받은 값 쓰기

문제 11 (만들어 보기)

문자열 리스트 items를 받아, 정수로 바꿀 수 있는 항목만 모두 더해 돌려주는 함수 add(items)를 만들어 봅니다. 정수로 바꿀 수 없는 문자열은 건너뜁니다. 뼈대의 마지막 줄이 이렇게 찍어야 합니다.

13

끝에 print(add(['2', 'y', '4'])) 한 줄을 더해 한 번 더 부르면 이렇게 나와야 합니다.

13
6

아래 뼈대에서 마지막 줄은 그대로 두고, 주석 셋 아래를 채우세요.

def add(items):
    # 1. 합을 0으로
    # 2. 정수로 바꿔 더하기
    # 3. 합 돌려주기


print(add(['5', 'x', '8']))

처음 펼 때 약 6MB를 받습니다.

힌트

for s in items: 안에서 try:로 total += int(s)를 실행하고, except ValueError:에서는 continue를 씁니다.

정답

모범 답입니다.

def add(items):
    # 1. 합을 0으로
    total = 0
    # 2. 정수로 바꿔 더하기
    for s in items:
        try:
            total += int(s)
        except ValueError:
            continue
    # 3. 합 돌려주기
    return total


print(add(['5', 'x', '8']))
실행 결과
13
  • 다르게 써도 되는 곳: n = int(s)와 total = total + n을 두 줄로 나누어 써도 같습니다.
  • 흔한 오답:
    • try / except를 for 반복문 바깥에 한 번만 감싸면 'x'에서 오류가 나는 순간 반복문 전체가 끝나 버려 뒤의 '8'을 더하지 못합니다(5만 돌려줌).
    • return total을 for 반복문 안에 들여 쓰면 첫 바퀴에서 함수가 끝나 버립니다.

다시 볼 레슨: try와 except · 합 모으기와 세기 · 돌려받은 값 쓰기

문제 12 (만들어 보기)

이번에는 빈 데서 씁니다. 주문 수량(count)으로 1 이상 10 이하의 정수가 들어올 때까지 다시 묻는 프로그램을 만들어 봅니다.

  • 프롬프트는 '수량: '으로 합니다.
  • 정수로 바꿀 수 없는 글자가 들어오면 '숫자만 됩니다'를 찍고 다시 묻습니다.
  • 정수로 바꿨지만 1 <= count <= 10이 아니면 '1~10만 됩니다'를 찍고 다시 묻습니다.
  • 두 관문을 모두 통과하면 반복을 끝내고 마지막에 '주문:', count를 찍습니다.

'세개', '0', '3'을 차례로 넣으면 이렇게 나와야 합니다.

수량: 세개
숫자만 됩니다
수량: 0
1~10만 됩니다
수량: 3
주문: 3

입력만 '열', '15', '10'으로 바꾸면 이렇게 나와야 합니다.

수량: 열
숫자만 됩니다
수량: 15
1~10만 됩니다
수량: 10
주문: 10
# 1. 계속 묻기

# 2. 바꿀 수 있는지 보기

# 3. 범위 맞으면 나가기넣는 값세개03

처음 펼 때 약 6MB를 받습니다.

힌트

맞는 값이 올 때까지 다시 묻기의 세 하위 목표(while True: → try / except ValueError:⁠와 continue → if 1 <= count <= 10: break)⁠를 차례대로 씁니다.

정답

모범 답입니다.

while True:
    raw = input('수량: ')
    try:
        count = int(raw)
    except ValueError:
        print('숫자만 됩니다')
        continue
    if 1 <= count <= 10:
        break
    print('1~10만 됩니다')
print('주문:', count)넣는 값세개03
실행 결과
수량: 세개
숫자만 됩니다
수량: 0
1~10만 됩니다
수량: 3
주문: 3
  • 다르게 써도 되는 곳: 1 <= count <= 10은 count >= 1 and count <= 10⁠으로 써도 같습니다.
  • 흔한 오답:
    • except ValueError: 안에 continue를 빼먹으면 '세개'를 넣었을 때 count가 만들어지지 않은 채로 if 1 <= count <= 10:으로 내려가 NameError가 납니다.
    • 조건을 1 < count < 10으로 쓰면 경계 값인 10(둘째 시험 값)이 거부됩니다.

다시 볼 레슨: 맞는 값이 올 때까지 다시 묻기 · try와 except · while과 추적 표

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

파이썬 목차로