14. 오류와 예외 처리#
프로그램을 구현하다보면 여러 종류의 오류를 경험한다. 프로그래밍 과정 중에 가장 많이 발생하는 오류와 대처방안을 소개한다.
14.1. 오류와 디버깅#
프로그램의 오류는 크게 세 가지 유형으로 나뉜다. 오류가 발생하면 프로그램 개발자는 오류의 원인을 찾아 해결해야 한다. 이렇게 프로그램의 오류를 찾아 해결하는 과정을 디버깅debugging이라 부르며, 파이썬 실행기는 오류가 발생할 경우 디버깅에 도움되는 정보를 제공한다.
14.1.1. 구문 오류#
구문 오류syntax error는 명령문을 작성할 때 지켜야 하는 명령문 문법에 어긋나는 오류가 있음을 의미한다. 파이썬 실행기는 프로그램을 실행하기 전에 문법 검사를 통해 모든 구문 오류를 찾아낸다.
예제: 변수 선언 과정
변수를 선언할 때 변수로 False, if, return 등
파이썬에서 특별한 기능을 갖는 키워드를 사용하거나,
bad name, odd~job, US$ 등처럼
허용되지 방식을 사용하면 SyntaxError와
같은 구문 오류가 발생한다.
False = 0
Cell In[3], line 1
False = 0
^
SyntaxError: cannot assign to False
bad name = 5
Cell In[2], line 1
bad name = 5
^
SyntaxError: invalid syntax
예제: 반복문 선언 과정
for 반복문을 작성할 때 콜론 기호 :를 생략하거나 본문 들여쓰기를 하지 않은 경우에는
종류에 따라 SyntaxError, IndentationError 등이 발생한다.
for i in range(5)
print(i)
Cell In[1], line 1
for i in range(5)
^
SyntaxError: expected ':'
for i in range(5):
j = i + 1
print(j)
Cell In[5], line 2
j = i + 1
^
IndentationError: expected an indented block after 'for' statement on line 1
14.1.2. 런타임 오류#
런타임 오류runtime error는 프로그램이 실행되는 도중에 발생하는 오류이다. 프로그램의 실행을 중단시키는 예외 상황이라는 의미에서 런타임 오류를 예외exception라고 부르기도 한다. 런타임 오류는 다양한 경우에 발생한다. 여기서는 네 종류의 런타임 오류를 살펴본다.
런타임 오류 예제 1: 0으로 나누기 오류
런타임 에러의 대표적인 예는 0으로 나누기 오류다.
ZeroDivisionError 라고 표시되는데,
이는 num이 0을 가리키고 있기에 결국 0으로 나눗셈을 시도하기 때문에 발생한다.
num = 0
print(3 / num)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[6], line 2
1 num = 0
----> 2 print(3 / num)
ZeroDivisionError: division by zero
참고로 3/num은 구문syntax 측면에서는 전혀 문제 없다.
이유는 실제로 3/num이 계산될 때까지는
변수 num에 할당된 값이 0이 될 수도, 되지 않을 수도 있기에
겉모양만 보고는 실행이 가능한지 여부를 알 수 없기 때문이다.
런타임 오류 예제 2: 변수 이름 오류
아래 코드를 실행하면 a_number 라는 변수가 선언되어 있지 않기 때문에 문제가 발생한다.
NameError라고 표시되는데, 이 오류는 선언되지 않은 변수가 사용될 때 발생한다.
자세히 살펴보면 a_number와 a_Number 둘 중에 하나는 오타임을 알 수 있다.
a_Number = 327.68
b = a_number * 3
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[7], line 2
1 a_Number = 327.68
----> 2 b = a_number * 3
NameError: name 'a_number' is not defined
런타임 오류 예제 3: 자료형 오류
아래 코드는 float() 함수를 리스트와 함께 호출한다.
그런데 float() 함수는 str, int, float 세 종류의 자료형만 인자로 사용하기로 정의되어 있다.
따라서 함수 인자의 자료형이 틀렸다는 의미의 TypeError가 발생하며 코드의 실행이 멈춘다.
따라서 마지막 print() 함수의 호출은 실행되지 않는다.
x = [1, 2]
print(float(x))
print("프로그램 실행 완료!")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[8], line 3
1 x = [1, 2]
----> 3 print(float(x))
4 print("프로그램 실행 완료!")
TypeError: float() argument must be a string or a real number, not 'list'
런타임 오류 예제 4: 값의 형식 오류
아래 코드는 float() 함수를 123f2라는 문자열을 가리키는 변수 x와 함께 호출한다.
인자의 자료형이 str 이기에 float() 함수의 인자로 사용될 자격이 있다.
하지만 지정된 문자열이 부동소수점 형식이 아니기에 인자의 형식이 올바르지 않다는 의미의
ValueError가 발생하며 코드의 실행이 멈춘다.
따라서 마지막 print() 함수의 호출은 실행되지 않는다.
x = '123f2'
print(float(x))
print("프로그램 실행 완료!")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[9], line 3
1 x = '123f2'
----> 3 print(float(x))
4 print("프로그램 실행 완료!")
ValueError: could not convert string to float: '123f2'
14.1.3. 의미 오류#
프로그램은 오류 없이 잘 실행되지만 원하는 결과를 만들지 못한다면 프로그램 어딘가에 논리적 오류가 존재한다는 의미이다. 이와같은 오류를 의미 오류semantic error라 부른다. 의미 오류의 발생원인은 매우 다양하다.
프로그램이 정상적으로 작동하기 때문에 구문 오류나 런타임 오류와는 다르게 오류의 원인을 바로 확인하기 어렵거나 아예 불가능할 수도 있다. 수학 문제를 풀다가 계산 실수를 하거나, 기호를 다르게 적거나, 문제를 잘못 이해했거나 해서 풀 수 있었던 문제를 틀렸던 경험이 있을 것이다. 프로그래밍에서도 유사한 실수가 많이 발생한다.
예를 들어, 아래 프로그램은 두 배 계산 대신에 제곱 계산을 하는 실수를 범한 경우이다.
num = 3
doubleNum = num ** 2
print("입력한 값", num, "의 두 배는", doubleNum, "입니다.")
입력한 값 3 의 두 배는 9 입니다.
두 배하려면 num * 2를 사용했어야 하는데 실수로 num ** 2를 사용하여서
결과적으로 입력한 값의 제곱을 계산하게 된다.
수천, 수만 줄로 이루어진 프로그램에서 이런 형식의 오류의 원인을 찾는 일은
경우에 따라 모래사장에서 바늘찾기처럼 매우 어렵거나 불가능할 수 있다.
14.2. 예외 처리#
오류가 발생할 수 있는 상황에 미리 대처하는 코딩 기법을 예외 처리exception handling라 부른다. 가장 단순한 예외 처리 형식은 다음과 같다.
try:
code1
except:
code2
위 코드의 의미는 다음과 같다.
먼저
try키워드의 본문인code1을 실행한다. 실행 과정 중에 오류가 발생하지 않으면except키워드의 본문인code2부분은 건너 뛴다.만약
code1실행중에 오류가 발생하면 프로그램의 실행을 멈추는 대신 바로 이어서code2를 실행한다.
예를 들어 아래 코드는
ValueError로 인해 코드 실행이 멈추는 대신
입력값에 어떤 문제가 있는지 정보를 출력한다.
이유는 try의 본문에 있는 코드가 실행할 때 오류가 발생하면
바로 except의 본문에 있는 코드가 실행되도록 약속되었기 때문이다.
또한 코드의 실행은 계속 이어져서 마지막 줄의 print() 함수도 호출되어
프로그램이 제대로 실행되었음을 확인해준다.
x = '123f2'
try:
print(float(x))
except:
print('부동소수점 모양의 문자열이 아닙니다.')
print("프로그램 실행 완료!")
부동소수점 모양의 문자열이 아닙니다.
프로그램 실행 완료!
오류의 종류를 지정하는 예외 처리
특정 종류의 오류가 발생할 때만 예외 처리를 실행하도록 할 수 있다.
예를 들어 아래 형식은
ValueError가 발생할 때만 예외 처리를 실행한다.
try:
code1
except ValueError:
code2
아래 코드를 실행하면 ValueEror 오류가 발생한다.
x = '123f2'
print(float(x))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[12], line 3
1 x = '123f2'
----> 3 print(float(x))
ValueError: could not convert string to float: '123f2'
아래 코드는 ValueError가 발생했을 때의 예외 처리를 지정한다.
x = '123f2'
try:
print(float(x))
except ValueError:
print('부동소수점 모양의 문자열이 아닙니다.')
print("프로그램 실행 완료!")
부동소수점 모양의 문자열이 아닙니다.
프로그램 실행 완료!
오류의 종류를 명시하면 다른 종류의 오류는 처리하지 못한다.
예를 들어 아래 코드는 float() 함수의 인자로 튜플이 입력되어 TypeError 오류가 발생한다.
그런데 ValueError만 처리하도록 설정되어 있어서
예외 처리가 제대로 실행되지 못하고 결국에 프로그램 실행이 중간에 멈춰버린다.
x = [1, 2]
try:
print(float(x))
except ValueError:
print('부동소수점 모양의 문자열이 아닙니다.')
print("프로그램 실행 완료!")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[13], line 4
1 x = [1, 2]
3 try:
----> 4 print(float(x))
5 except ValueError:
6 print('부동소수점 모양의 문자열이 아닙니다.')
TypeError: float() argument must be a string or a real number, not 'list'
이에 대한 해결책은 오류의 종류를 명시하지 않거나 아래처럼 여러 종류의 오류를 처리하도록 지정하는 것이다.
x = [1, 2]
try:
print(float(x))
except (ValueError, TypeError):
print('사용된 인자에 문제가 있습니다.')
print("프로그램 실행 완료!")
사용된 인자에 문제가 있습니다.
프로그램 실행 완료!
14.3. 예제#
예제 1
명령문을 실행해서 발생하는 오류의 종류와 원인을 아래 형식의 예외 처리를 이용하여 설명하라.
try:
명령문1
except 오류종류 as err:
print(f"(오류 설명) 오류종류: {err}")
위 코드의 명령문1을 실행할 때 오류종류에 해당하는 오류가 발생하면
err은 오류가 발생한 이유를 설명하는 문자열이 지정된다.
따라서 오류의 발생원인을 담은 문장이 화면에 출력된다.
반면에 SyntaxError, IndentationError 등은 프로그램을 실행하기 전에 발견되는
오류이기에 try-except 명령문을 사용할 의미가 없다.
이런 경우엔 오류의 원인을 찾아 제거하라.
(1)
try = "시도해봐!"
Cell In[1], line 1
try = "시도해봐!"
^
SyntaxError: expected ':'
답:
SyntaxError발생:try는 예외처리에 사용되는 키워드이며 따라서 변수명으로 허용되지 않음.
SyntaxError는 코드를 실행하기 전에 발생하는 오류이기 때문에
try-except 명령문으로 감싸더라도 계속해서 SyntaxError가 발생한다.
따라서 아래 코드에서처럼 try1 등 다른 변수명을 사용해야 한다.
try1 = "시도해봐!"
(2)
L1 = [1, 2, 3]
print(L1[3])
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[3], line 2
1 L1 = [1, 2, 3]
----> 2 print(L1[3])
IndexError: list index out of range
답:
IndexError발생: 길이가n인 리스트에 사용할 수 있는 인덱스는-n부터n-1사이의 정수만 해당함.
len(L1)
3
아래와 같이 코드를 수정한다.
L1 = [1, 2, 3]
try:
print(L1[3])
except IndexError as err:
print(f"(오류 설명) IndexError: {err}")
(오류 설명) IndexError: list index out of range
(3)
for i in range(5) :
i -= 2
print(i)
Cell In[6], line 3
print(i)
^
IndentationError: unexpected indent
답:
IndentationError발생:for반복문의 본문은 아래 코드처럼 들여쓰기가 일정해야 함.
IndentationError 또한 코드를 실행하기 전에 발생하는 오류이기 때문에
try-except 명령문으로 감싸더라도 계속해서 SyntaxError가 발생한다.
try:
for i in range(5) :
i -= 2
print(i)
except:
print(f"(오류 설명) IndexError: {err}")
Cell In[10], line 4
print(i)
^
IndentationError: unexpected indent
따라서 아래 처럼 코드를 바로 수정하는 수밖에 없다.
for i in range(5) :
i -= 2
print(i)
-2
-1
0
1
2
(4)
x = 27
if x % 3 == 0
print(x, "는(은) 3의 배수")
Cell In[8], line 3
if x % 3 == 0
^
SyntaxError: expected ':'
답:
SyntaxError발생:if 논리식명령문은 아래 코드처럼 항상 콜론(:)으로 마무리 해야 함.
SyntaxError는 코드를 실행하기 전에 발생하는 오류이기 때문에
try-except 명령문으로 감싸더라도 계속해서 SyntaxError가 발생한다.
따라서 아래 처럼 코드를 바로 수정하는 수밖에 없다.
x = 27
if x % 3 == 0:
print(x, "는(은) 3의 배수")
27 는(은) 3의 배수
예제 2
아래처럼 출력을 하는 코드를 구현하려 한다.
* * * * *
* * * *
* * *
* *
*
*
* *
* * *
* * * *
* * * * *
그런데 아래 코드를 실행하면 원하는 모양이 출력되지 않는다.
num = 0
while num < 10:
if num < 5:
stars = 5 - num
else:
stars = num - 4
print("* " * stars)
num += 1
* * * * *
* * * *
* * *
* *
*
*
* *
* * *
* * * *
* * * * *
위 코드를 수정하여 원하는 모양이 출력되도록 하라.
힌트: 각 행에서 공백 출력을 먼저하도록 한다. 그러기 위해 몇 개의 공백을 출력해야할지 정하는 변수 spaces를 선언해서 활용한다.
그런다음 위 코드에 공백 출력과 관련된 부분만 새롭게 추가한다.
답:
위 코드에서 별을 출력하는 부분은 정확함.
다만 별 출력 이전에 공백을 추가해야 하기에 출력에 필요한 공백의 크기를 정해야 함.
num이 0부터 4까지 변할 때 공백크기는 0부터 8까지 2씩 커짐:spaces = num * 2num이 5부터 9까지 변할 때 공백크기는 8부터 0까지 2씩 작아짐:spaces = (9-num) * 2결론: 아래 코드에서처럼
spaces변수 선언문을 경우에 따라 다르게 선언한 후에print()함수를 살짝 수정하면 됨.
num = 0
while num < 10:
if num < 5:
stars = 5 - num
spaces = num * 2
else:
stars = num - 4
spaces = (9 - num) * 2
print(" " * spaces + "* " * stars)
num += 1
* * * * *
* * * *
* * *
* *
*
*
* *
* * *
* * * *
* * * * *
예제 3
아래처럼 출력하는 코드를 구현하려 한다.
[0, 1]
[0, 2]
[0, 3]
[1, 2]
[1, 3]
[2, 3]
그런데 아래 코드를 실행하면 원하는 모양이 출력되지 않는다.
i = 0
while i < 4:
j = 0
while j < 4:
if j > i:
print([j, i])
j += 1
i += 1
[1, 0]
[2, 0]
[3, 0]
[2, 1]
[3, 1]
[3, 2]
위 코드를 수정하여 원하는 모양이 출력되도록 하라.
힌트: 한 행의 코드만 수정하면 된다.
답:
i와j가 0부터 3까지 변할 때j > i일 때만print()함수 실행그런데 출력되는 어레이의 0번과 1번 인덱스의 값의 위치가 서로 바뀜.
따라서
print([i, j])를print([j, i])대신 사용.
i = 0
while i < 4:
j = 0
while j < 4:
if j > i:
print([i, j])
j += 1
i += 1
[0, 1]
[0, 2]
[0, 3]
[1, 2]
[1, 3]
[2, 3]
예제 4
문자열을 인자로 입력받을 때
부동소수점 형식이면 부동소수점으로 변환된 값을,
아니면 문자열 그대로를 반환하는 함수 whether_float()를
예외 처리를 이용하여 구현하라.
답:
변수 x가 가리키는 문자열이 부동소수점 형식을 갖추지 못한 경우 float(x)를 호출하면
ValueError 오류가 발생한다.
x = '3.14abc'
float(x)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[13], line 2
1 x = '3.14abc'
----> 2 float(x)
ValueError: could not convert string to float: '3.14abc'
반면에 부동소수점 형식이면 정상적으로 부동소수점으로 변환된 값을 반환한다.
x = '3.14159'
float(x)
3.14159
따라서 x가 주어졌을 때 float(x)를 먼저 실행한 다음
오류가 발생할 경우에 대해 예외처리를 진행한다.
아래 whether_float() 함수는 오류가 발생할 경우 x를 반환하도록 설정되었다.
def whether_float(x):
try:
return float(x)
except:
return x
whether_float('3.14159')
3.14159
whether_float('3.14abc')
'3.14abc'
whether_float('부동소수점 모양의 문자열이 아닙니다.')
'부동소수점 모양의 문자열이 아닙니다.'
예외처리 단계에서 ValueError 만을 다루게 할 수도 있다.
def whether_float(x):
try:
return float(x)
except ValueError:
return x
whether_float('3.14159')
3.14159
whether_float('3.14abc')
'3.14abc'
whether_float('부동소수점 모양의 문자열이 아닙니다.')
'부동소수점 모양의 문자열이 아닙니다.'
예제 5
문자열 인덱싱을 이용하여 문자열에 포함된 문자를 확인할 수 있다. 예를 들어 첫째 문자는 0을, 셋째 문자는 2를 인덱스로 활용한다.
a_string = 'python'
a_string[0]
'p'
a_string[2]
't'
그런데 인덱스로 사용될 수 있는 정수들의 범위는 문자열에 따라 달라진다.
python 문자열이 6개의 문자로 구성되었기에 인덱스로 사용될 수 있는 정수는
0부터 5까지 또는 -6부터 -1까지이다.
그 이외의 정수에 대해서는 아래처럼 IndexError가 발생한다.
a_string[6]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[25], line 1
----> 1 a_string[6]
IndexError: string index out of range
a_string[-7]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[26], line 1
----> 1 a_string[-7]
IndexError: string index out of range
질문:
-10부터 10까지의 정수 n에 대해 a_string[n]을 출력하는 for 반복문을 작성하라.
단, IndexError 오류가 발생할 경우 “인덱스 범위 벗어남”을 출력하라.
힌트: try ... except IndexError: 명령문 활용
답:
n이 -10부터 10까지 변할 때 먼저a_string[n]을 실행하도록 함n이 허용된 범위를 넘어설 경우IndexError가 발생할 것이기에 이에 대해 아래 코드처럼 예외처리 실행.n이 -6부터 -1까지 변할 때 한 번, 그리고 0부터 5까지 변할 때 또 한 번 전체 문자가 출력됨.
a_string = "python"
for n in range(-10, 11):
try:
print(a_string[n])
except IndexError:
print("인덱스 범위 벗어남")
인덱스 범위 벗어남
인덱스 범위 벗어남
인덱스 범위 벗어남
인덱스 범위 벗어남
p
y
t
h
o
n
p
y
t
h
o
n
인덱스 범위 벗어남
인덱스 범위 벗어남
인덱스 범위 벗어남
인덱스 범위 벗어남
인덱스 범위 벗어남
예제 6
숫자 야구 게임은 임의로 정한 세 자리의 수를 참여자가 맞히는 게임이며 규칙은 다음과 같다.
첫째, 1에서 9 사이의 서로 다른 숫자로 이루어진 세 자리 정수를 입력한다.
둘째, 세 자리 숫자를 정확하게 맞혔으면
'홈런'을 출력한다.셋째, 세 자리수를 정확하게 맞히지 못했다면 참여자가 입력한 수가 맞혀야 하는 세 자리 수와 어떻게 다른지 여부에 따라 참여자에게 아래 규칙에 따른 결과를 출력한다.
숫자와 위치가 맞으면, 스트라이크
숫자는 맞지만 위치가 틀리면, 볼
숫자와 위치가 모두 틀리면, 아웃
예를 들어, 맞혀야 하는 수가 123일 때 다음과 같이 출력한다.
참여자가 123을 입력할 때:
'홈런'참여자가 456을 입력할 때:
'아웃'참여자가 257을 입력할 때:
'1 볼'참여자가 273을 입력할 때:
'1 볼 1 스트라이크'
아래 코드는 숫자 야구 게임을 실행한다. 사용자의 입력값이 정수가 아니면 세 자리 정수를 다시 입력하도록 요구한다.
answer = str(123)
while True:
guess = input('1에서 9사이의 서로 다른 숫자로 구성된 세자리 정수를 입력하세요: ')
# 정수 입력 여부 확인
try:
int(guess)
except ValueError:
continue
ball = 0
strike = 0
for i in range(3):
if answer[i] == guess[i]:
strike += 1
elif guess[i] in answer:
ball += 1
if strike == 3:
print('홈런')
elif strike == 0:
if ball == 0:
print('아웃')
else:
print(ball, '볼')
else:
if ball == 0:
print(strike, '스트라이크')
else:
print(ball, '볼', strike, '스트라이크')
break
1에서 9사이의 서로 다른 숫자로 구성된 세자리 정수를 입력하세요: 25.77
1에서 9사이의 서로 다른 숫자로 구성된 세자리 정수를 입력하세요: 456
아웃
질문:
위 코드는 하지만 맞혀야 하는 수가 123으로 고정되었다. 맞혀야 하는 세 자리의 수가 무작위로 지정되도록 위 코드를 수정하라. 단 숫자 0은 절대로 포함되지 않아야 한다.
힌트: random.randint() 함수 활용
답:
세 자리수 생성을 위해
random.randint(100, 999)사용을 사용하면 0을 포함하지 않아야 한다는 조건믈 만족시키기 어려움대신
random.randint(1, 9)를 세 번 호출하여 0을 포함하지 않는 세 자리수 모양의 문자열 생성 가능.이를 위해 아래 코드 활용:
random.randint(1, 9)함수를 세 번 호출하여 세 개의 정수로 구성된 문자열 생성.answer = '' for _ in range(3): answer += str(random.randint(1, 9))
import random
# 맞혀야 하는 세 자리 수 생성. 0을 포함하지 않음.
answer = ''
while len(answer) < 3:
num = str(random.randint(1, 9))
if num in answer:
continue
answer += num
# 게임 실행
while True:
guess = input('1에서 9사이의 서로 다른 숫자로 구성된 세자리 정수를 입력하세요: ')
# 정수 입력 여부 확인
try:
int(guess)
except ValueError:
continue
ball = 0
strike = 0
for i in range(3):
if answer[i] == guess[i]:
strike += 1
elif guess[i] in answer:
ball += 1
if strike == 3:
print('홈런')
elif strike == 0:
if ball == 0:
print('아웃')
else:
print(ball, '볼')
else:
if ball == 0:
print(strike, '스트라이크')
else:
print(ball, '볼', strike, '스트라이크')
break
1에서 9사이의 서로 다른 숫자로 구성된 세자리 정수를 입력하세요: abc
1에서 9사이의 서로 다른 숫자로 구성된 세자리 정수를 입력하세요: 876
1 볼
예제 7
아래 코드는 secret 변수에 할당된 17을 맞힐 때까지 정수입력을 반복시킨다.
print("수 알아맞히기 게임에 환영합니다.")
secret = 17
guess = -1 # 이어지는 while 반복문이 최소 한 번은 실행되도록 함
while guess != secret:
guess = int(input("1부터 100 사이의 정수 하나를 입력하세요: "))
if guess == secret:
print("맞았습니다!")
elif guess > secret:
print("너무 커요!")
else:
print("너무 작아요!")
print("게임 종료!")
수 알아맞히기 게임에 환영합니다.
1부터 100 사이의 정수 하나를 입력하세요: 50
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 25
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 12
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 18
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 14
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 16
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 17
맞았습니다!
게임 종료!
(1) 그런데 위 코드는 secret가 가리키는 값이 일정하기에
한 번 실행한 다음에는 더 이상 재미가 없어진다.
게임이 실행될 때마다
secret가 가리키는 값이 1과 100까지의 정수 중에서 임의로 지정되도록
위 코드를 수정하라.
힌트: random 모듈의 randint() 함수 활용
답:
secret 변수가 가리키는 값을 1부터 100 사이의 값으로 임의로 지정하기 위해
random.randint() 함수를 다음과 같이 이용한다.
from random import randint
secret = randint(1, 100)
이전 코드에 추가하면 다음과 같다.
from random import randint
print("수 알아맞히기 게임에 환영합니다.")
secret = randint(1, 100)
guess = -1 # 이어지는 while 반복문이 최소 한 번은 실행되도록 함
while guess != secret:
guess = int(input("1부터 100 사이의 정수 하나를 입력하세요: "))
if guess == secret:
print("맞았습니다!")
elif guess > secret:
print("너무 커요!")
else:
print("너무 작아요!")
print("게임 종료!")
수 알아맞히기 게임에 환영합니다.
1부터 100 사이의 정수 하나를 입력하세요: 50
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 25
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 12
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 6
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 3
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 4
맞았습니다!
게임 종료!
(2) 참여자가 몇 번 시도하여 정답을 맞혔는지 게임이 종료되면서 출력되도록 이전 질문의 답으로 사용된 코드를 수정하라. 예를 들어, 7 번 만에 답을 맞혔다만 다음처럼 출력되어야 한다.
7 번 만에 비밀을 맞혔습니다.
답:
참여자가 정답을 맞히려는 시도 횟수는 while 반복문의 실행횟수에 해당한다.
따라서 while 반복문 실행횟수를 기억하는 count 변수를 활용하면 다음과 같다.
from random import randint
print("수 알아맞히기 게임에 환영합니다.")
secret = randint(1, 100)
guess = -1 # 이어지는 while 반복문이 최소 한 번은 실행되도록 함
count = 0
while guess != secret:
guess = int(input("1부터 100 사이의 정수 하나를 입력하세요: "))
count += 1
if guess == secret:
print("맞았습니다!")
elif guess > secret:
print("너무 커요!")
else:
print("너무 작아요!")
print(count, "번 만에 비밀을 맞혔습니다.")
print("게임 종료!")
수 알아맞히기 게임에 환영합니다.
1부터 100 사이의 정수 하나를 입력하세요: 50
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 25
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 37
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 31
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 34
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 32
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 33
맞았습니다!
7 번 만에 비밀을 맞혔습니다.
게임 종료!
(3) 위 코드를 수정하여 정수 입력이 아닌 경우에 재입력을 요구하도록 하라.
힌트: try ... except ... 명령문과 continue 명령문 활용
답:
정수 입력이 아니면 int() 함수에 의해 ValueError 오류가 발생한다.
따라서 오류가 발생할 경우를 대비해서 try ... except ... 명령문으로 예외처리를
다음과 같이 하면 된다.
try:
guess = int(input("1부터 100 사이의 정수 하나를 입력하세요: "))
except:
continue
from random import randint
print("수 알아맞히기 게임에 환영합니다.")
secret = randint(1, 100)
guess = -1 # 이어지는 while 반복문이 최소 한 번은 실행되도록 함
while guess != secret:
try:
guess = int(input("1부터 100 사이의 정수 하나를 입력하세요: "))
except:
continue
if guess == secret:
print("맞았습니다!")
elif guess > secret:
print("너무 커요!")
else:
print("너무 작아요!")
print("게임 종료!")
수 알아맞히기 게임에 환영합니다.
1부터 100 사이의 정수 하나를 입력하세요: 45.789
1부터 100 사이의 정수 하나를 입력하세요: abc
1부터 100 사이의 정수 하나를 입력하세요: 50
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 75
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 62
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 68
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 65
너무 커요!
1부터 100 사이의 정수 하나를 입력하세요: 63
너무 작아요!
1부터 100 사이의 정수 하나를 입력하세요: 64
맞았습니다!
게임 종료!
14.4. 연습문제#
참고: (연습) 오류와 예외 처리