아래 코드는 input()
함수를 이용하여 사용자로부터 숫자를 입력받아
그 숫자의 제곱을 리턴하는 내용을 담고 있다.
코드를 실행하면 숫자를 입력하라는 창이 나오며,
여기에 숫자 3을 입력하면 정상적으로 작동한다.
하지만, 예를 들어, 3.2를 입력하면 값 오류(value error)가 발생한다.
In [1]:
input_number = input("A number please: ")
number = int(input_number)
print("제곱의 결과는", number**2, "입니다.")
In [2]:
input_number = input("A number please: ")
number = int(input_number)
print("제곱의 결과는", number**2, "입니다.")
위 코드는 정수들의 제곱을 계산하는 프로그램이다. 하지만 사용자가 경우에 따라 정수 이외의 값을 입력하면 시스템이 다운된다. 이에 대한 해결책을 다루고자 한다.
In [3]:
sentence = 'I am a sentence
오류를 확인하는 메시지가 처음 볼 때는 매우 생소하다. 위 오류 메시지를 간단하게 살펴보면 다음과 같다.
File "<ipython-input-3-a6097ed4dc2e>", line 1
1번 줄에서 오류 발생
sentence = 'I am a sentence
^
오류 발생 위치 명시
SyntaxError: EOL while scanning string literal
오류 종류 표시: 문법 오류(SyntaxError)
In [4]:
a = 0
4/a
앞서 예제들을 통해 살펴 보았듯이 다양한 종류의 오류가 발생하며, 코드가 길어지거나 복잡해지면 오류가 발생할 가능성은 점차 커진다. 오류의 종류를 파악하면 어디서 왜 오류가 발생하였는지를 보다 쉽게 파악하여 코드를 수정할 수 있게 된다.
따라서 코드의 발생원인을 바로 알아낼 수 있어야 하며 이를 위해서는 오류 메시지를 제대로 확인할 수 있어야 한다. 하지만 여기서는 언급된 예제 정도의 수준만 다루고 넘어간다.
코딩을 하다 보면 어차피 다양한 오류와 마주치게 될 텐데 그때마다 스스로 오류의 내용과 원인을 확인해 나가는 과정을 통해 보다 많은 경험을 쌓는 길 외에는 달리 방법이 없다.
코드에 문법 오류가 포함되어 있는 경우 아예 실행되지 않는다. 그렇지 않은 경우에는 일단 실행이 되고 중간에 오류가 발생하면 바로 멈춰버린다.
이렇게 중간에 오류가 발생할 수 있는 경우를 미리 생각하여 대비하는 과정을 예외 처리(exception handling)라고 부른다.
예를 들어, 오류가 발생하더라도 오류발생 이전까지 생성된 정보들을 저장하거나, 오류발생 이유를 좀 더 자세히 다루거나, 아니면 오류발생에 대한 보다 자세한 정보를 사용자에게 알려주기 위해 예외 처리를 사용한다.
사용방식은 다음과 같다.
try:
코드1
except:
코드2
In [5]:
number_to_square = input("정수를 입력하세요: ")
# number_to_square 변수의 자료형이 문자열(str)임에 주의하라.
# 따라서 연산을 하고 싶으면 정수형(int)으로 형변환을 먼저 해야 한다.
number = int(number_to_square)
print("제곱의 결과는", number**2, "입니다.")
In [6]:
number_to_square = input("정수를 입력하세요: ")
# number_to_square 변수의 자료형이 문자열(str)임에 주의하라.
# 따라서 연산을 하고 싶으면 정수형(int)으로 형변환을 먼저 해야 한다.
number = int(number_to_square)
print("제곱의 결과는", number**2, "입니다.")
3.2를 입력했을 때 오류가 발생하는 이유는 int()
함수가 정수 모양의 문자열만
처리할 수 있기 때문이다.
사실 정수들의 제곱을 계산하는 프로그램을 작성하였지만 경우에 따라
정수 이외의 값을 입력하는 경우가 발생하게 되며, 이런 경우를 대비해야 한다.
즉, 오류가 발생할 것을 미리 예상해야 하며, 어떻게 대처해야 할지 준비해야 하는데,
try ... except ...
문을 이용하여 예외를 처리하는 방식을 활용할 수 있다.
In [7]:
number_to_square = input("정수를 입력하세요: ")
try:
number = int(number_to_square)
print("제곱의 결과는", number ** 2, "입니다.")
except:
print("정수를 입력해야 합니다.")
올바른 값이 들어올 때까지 입력을 요구할 수 있다.
In [9]:
while True:
try:
number = int(input("정수를 입력하세요: "))
print("제곱의 결과는", number**2, "입니다.")
break
except:
print("정수를 입력해야 합니다.")
오류 종류에 맞추어 다양한 대처를 하기 위해서는 오류의 종류를 명시하여 예외처리를 하면 된다. 아래 코드는 입력 갑에 따라 다른 오류가 발생하고 그에 상응하는 방식으로 예외처리를 실행한다.
In [10]:
number_to_square = input("정수를 입력하세요: ")
try:
number = int(number_to_square)
a = 5/(number - 4)
print("결과는", a, "입니다.")
except ValueError:
print("정수를 입력해야 합니다.")
except ZeroDivisionError:
print("4는 빼고 하세요.")
In [12]:
number_to_square = input("A number please: ")
try:
number = int(number_to_square)
a = 5/(number - 4)
print("결과는", a, "입니다.")
except ValueError:
print("정수를 입력해야 합니다.")
except ZeroDivisionError:
print("4는 빼고 하세요.")
주의: 이와 같이 발생할 수 예외를 가능한 한 모두 염두하는 프로그램을 구현해야 하는 일은 매우 어려운 일이다.
앞서 보았듯이 오류의 종류를 정확히 알 필요가 발생한다.
다음 예제에서 보듯이 오류의 종류를 틀리게 명시하면 예외 처리가 제대로 작동하지 않는다.
In [13]:
try:
a = 1/0
except ValueError:
print("This program stops here.")
In [14]:
def to_define():
"""아주 복잡하지만 지금 당장 불필요"""
raise NotImplementedError("아직 정의되어 있지 않음")
In [15]:
print(to_define())
주의: 오류 처리를 사용하지 않으면 오류 메시지가 보이지 않을 수도 있음에 주의해야 한다.
In [16]:
def to_define1():
"""아주 복잡하지만 지금 당장 불필요"""
In [17]:
print(to_define1())
In [18]:
def square(number):
"""
정수를 인자로 입력 받아 제곱을 리턴한다.
"""
square_of_number = number * 2
return square_of_number
위 함수를 아래와 같이 호출하면 오류가 전혀 발생하지 않지만, 엉뚱한 값을 리턴한다.
In [19]:
square(3)
Out[19]:
주의: help()
를 이용하여 어떤 함수가 무슨 일을 하는지 내용을 확인할 수 있다.
단, 함수를 정의할 때 함께 적힌 문서화 문자열(docstring) 내용이 확인된다.
따라서, 함수를 정의할 때 문서화 문자열에 가능한 유효한 정보를 입력해 두어야 한다.
In [20]:
help(square)
파이썬에서 다루는 오류에 대한 보다 자세한 정보는 아래 사이트들에 상세하게 안내되어 있다.
파이썬 기본 내장 오류 정보 문서: https://docs.python.org/3.4/library/exceptions.html
파이썬 예외처리 정보 문서: https://docs.python.org/3.4/tutorial/errors.html
In [22]:
number_to_square = input("100을 나눌 숫자를 입력하세요: ")
number = int(number_to_square)
print("100을 입력한 값으로 나눈 결과는", 100/number, "입니다.")
아래 내용이 충족되도록 위 코드를 수정하라.
견본답안:
In [23]:
number_to_square = input("A number to divide 100: ")
try:
number = float(number_to_square)
print("100을 입력한 값으로 나눈 결과는", 100/number, "입니다.")
except ZeroDivisionError:
raise ZeroDivisionError('0이 아닌 숫자를 입력하세요.')
except ValueError:
raise ValueError('숫자를 입력하세요.')
In [24]:
number_to_square = input("A number to divide 100: ")
try:
number = float(number_to_square)
print("100을 입력한 값으로 나눈 결과는", 100/number, "입니다.")
except ZeroDivisionError:
raise ZeroDivisionError('0이 아닌 숫자를 입력하세요.')
except ValueError:
raise ValueError('숫자를 입력하세요.')
견본답안 1:
In [25]:
while True:
try:
a, b = input("정수 두 개를 입력하세요. 쉼표를 사용해야 합니다.\n").split(',')
a, b = int(a), int(b)
print("계산의 결과는", a/b, "입니다.")
break
except ValueError:
print("정수 두 개를 쉼표로 구분해서 입력해야 합니다.\n")
except ZeroDivisionError:
print("둘째 수는 0이 아니어야 합니다.\n")
견본답안 2: map
함수를 활용하여 a
, b
각각에 int
함수를 자동으로 적용할 수 있다.
map
함수에 대한 설명은 여기를 참조하면 된다.
In [26]:
while True:
try:
a, b = map(int, input("정수 두 개를 입력하세요. 쉼표를 사용해야 합니다.\n").split(','))
print("계산의 결과는", a/b, "입니다.")
break
except ValueError:
print("정수 두 개를 쉼표로 구분해서 입력해야 합니다.\n")
except ZeroDivisionError:
print("둘째 수는 0이 아니어야 합니다.\n")
키와 몸무게를 인자로 받아 체질량지수(BMI)를 구하는 코드를 작성하라. 아래 사항들을 참고한다.
$$BMI = \frac{weight}{height^2}$$kg
m
BMI
수치에 따른 체중 분류BMI <= 18.5
이면 저체중18.5 < BMI <= 23
이면 정상23 < BMI <= 25
이면 과체중25 < BMI <= 30
이면 비만BMI > 30
이면 고도비만견본답안:
In [27]:
while True:
try:
print("키와 몸무게를 입력하세요: ")
a, b = map(float, input().split(", "))
BMI = b/(a**2)
if BMI <= 18.5:
print("BMI는", BMI, "입니다. 저체중입니다.")
elif 18.5 < BMI <= 23:
print("BMI는", BMI, "입니다. 정상 체중입니다.")
elif 23 < BMI <= 25:
print("BMI는", BMI, "입니다. 비만입니다.")
elif 25 < BMI <= 30:
print("BMI는", BMI, "입니다. 과체중입니다.")
else:
print("BMI는", BMI, "입니다. 고도비만입니다.")
break
except ValueError:
print("숫자를 입력하세요.")
except ZeroDivisionError:
print("0이 아닌 숫자를 입력하세요.")