예외 처리

honeyricecake·2022년 6월 30일
0

파이썬

목록 보기
19/26

프로그램을 만들다 보면 수없이 많은 오류를 만나게 된다.
물론 오류가 발생하는 이유는 프로그램이 잘못 동작하는 것을 막기 위한 파이썬의 배려이다.
하지만 때때로 이러한 오류를 무시하고 싶을 때도 있다.

이를 위해 파이썬은 try, except를 사용해서 예외적으로 오류를 처리할 수 있게 해준다.

오류는 어떤 때 발생하는가?

디렉터리 안에 없는 파일을 열려고 시도했을 때

f = open("나 없는 파일","r")

FileNotFoundError: [Errno 2] No such file or directory: '나 없는 파일'
이 출력되는 것을 볼수 있다.

또한 0으로 다른 숫자를 나누는 경우 역시 자주 오류가 발생하고

리스트에서 없는 인덱스를 참조하려고 할 때 IndexError오류가 발생한다.

이런 오류가 발생하면 파이썬은 프로그램을 중단하고 오류 메시지를 보여준다.

오류 예외 처리 기법

try, except 문

다음은 오류 처리를 위한 try, except문의 기본 구조이다.

try:
	...
except: [발생 오류[as 오류 메시지 변수]]
	...

try 블록 수행 중 오류가 발생하면 except 블록이 수행된다. 하지만 try블록에서 오류가 발생하지 않는다면 except블록은 실행되지 않는다.

except구문을 자세히 살펴보자.

[] 기호를 사용하는 것을 볼 수 있는데 이 기호는 괄호 안의 내용을 생략할 수 있다는 관례 표기법이다.

즉, except구문은 다음 3가지 방법으로 사용할 수 있다.

  1. try, except만 쓰는 방법

이 경우는 오류 종류에 상관없이 오류가 발생하면 except블록을 수행한다.

  1. 발생오류만 포함한 except문

이 경우는 오류가 발생했을 때 except문에 미리 정해 놓은 오류 이름과 일치할 때만 except 블록을 수행한다는 뜻을 수행한다는 뜻이다.

  1. 발생 오류와 오류 메시지 변수까지 포함한 except문

이 경우는 두번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용하는 방법이다.

이 방법의 예를 들어보면 다음과 같다.

try:
	4/0
except ZeroDivisionError as e:
	print(e)

division by zero 가 출력되는 것을 볼 수 있다.

try .. finally

try 문에는 finally 절을 사용할 수 있다.

finally 절은 try문 수행 도중 예외 발생 여부에 상관없이 항상 수행된다.

보통 finally 절은 사용한 리소스를 close해야 할 때에 많이 사용한다.
(에러의 발생 여부와 상관없이 수행해야 하는 코드)

f = open('foo.txt', 'w')
try:
    # 무언가를 수행한다.
finally:
    f.close()

여러 개의 오류 처리하기

try문 안에서 여러 개의 오류를 처리하기 위해 다음 구문을 사용한다.

try:
    ...
except 발생 오류1:
   ... 
except 발생 오류2:
   ...

즉, 0으로 나누는 요류와 인덱싱 오류를 다음과 같이 처리할 수 있다.

try:
    a = [1,2]
    print(a[3])
    4/0
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
except IndexError:
    print("인덱싱 할 수 없습니다.")

a는 2개의 요솟값을 가지고 있기 때문에 a[3]은 IndexError를 발생시키므로 "인덱싱할 수 없습니다"라는 문자열이 출력될 것이다. 인덱싱 오류가 먼저 발생했으므로 4/0으로 발생되는 ZeroDivisionError 오류는 발생하지 않았다.

다음과 같이 ZeroDivisionErrorIndexError 를 함꼐 처리할 수도 있다.

try:
    a = [1,2]
    print(a[3])
    4/0
except (ZeroDivisionError, IndexError) as e:
    print(e)  # 어떤 오류가 발생했는지 출력을 통해 알 수 있다.

2개 이상의 오류를 동일하게 처리하기 위해서는 위와 같이 괄호를 사용하여 함꼐 묶어 처리하면 된다.

try문에 else절 사용하기

try문에는 다음처럼 else절을 사용할 수 있다.

try:
    ...
except [발생 오류[as 오류 메시지 변수]]:
    ...
else:  # 오류가 없을 경우에만 수행된다.
    ...

try문 수행 중 오류가 발생하면 except 절이 수행되고 오류가 없으면 else절이 수행된다.

다음은 try문에 else절을 활용하는 간단한 예이다.

try:
    age=int(input('나이를 입력하세요: '))
except:
    print('입력이 정확하지 않습니다.')
else:
    if age <= 18:
        print('미성년자는 출입금지입니다.')
    else:
        print('환영합니다.')

만약 나이를 입력하세요 라는 질문에 숫자가 아닌 다른 값을 입력하면 오류가 발생하여 입력이 정확하지 않습니다 라는 문장을 출력한다.

오류가 없을 경우에만 else절이 수행된다.

try:
	4/0
except ZeroDivisionError as e:
	print(e)

print(1)

이를 실행해보면 일반적으로는 에러가 발생해도 그 뒤는 그냥 실행됨을 알 수 있다.
그래서 else가 필요하다.

오류 회피하기

프로그래밍을 하다 보면 특정 오류가 발생할 경우 그냥 통과시켜야 할 때가 있다.

다음 예를 보자

try:
    f = open("나없는파일", 'r')
except FileNotFoundError:
    pass

try문안에 FileNotFound에러가 발생했을 때 pass를 사용하여 오류를 그냥 회피하도록 작성한 예제이다.

오류 일부러 발생시키기

종종 프로그래밍을 하다보면 오류를 일부러 발생시켜야 할 경우도 생긴다.

예를 들어 Bird 클래스를 상속받는 자식 클래스는 반드시 fly하는 함수를 구현하도록 만들고 싶은 경우(강제로 그렇게 하고 싶은 경우)가 있을 수 있다.

다음 예를 보자

class Bird:
    def fly(self):
        raise NotImplementedError

위 예제는 Bird 클래스를 상속받는 자식 클래스는 반드시 fly함수를 구현해야 한다는 의지를 보여준다.

(NotImplementedError는 파이썬 내장 오류로, 꼭 작성해야 하는 부분이 구현되지 않을 경우 일부러 오류를 일으키기 위해 사용한다.)

예외 만들기

프로그램 수행 도중 특수한 경우에만 예외 처리를 하기 위해서 종종 예외를 만들어서 사용한다.

직접 예외를 만들어 보자.

예외는 다음과 같이 파이썬 내장 클래스인 Exception 클래스를 상속하여 만들 수 있다.

class MyError(Exception):
	pass

그리고 별명을 출력해주는 함수를 다음과 같이 작성한다.

def say_nick(nick):
	if nick == '바보':
    	raise MyError()
    print(nick)

이는 다음과 같이 예외처리를 할 수 있다.

try:
    say_nick("천사")
    say_nick("바보")
except MyError:
    print("허용되지 않는 별명입니다.")

오류 메시지를 사용하고 싶다면 다음과 같이 할 수 있다.

try:
    say_nick("천사")
    say_nick("바보")
except MyError as e:
    print(e)

하지만 프로그램을 실행해보면 print(e) 로 오류메시지가 출력되지 않는 것을 확인할 수 있다. 오류 메시지를 출력했을 때 오류 메시지가 보이게 하려면 오류 클래스에 다음과 같은 __str__ 메서드를 구현해야 한다.

class MyError(Exception):
    def __str__(self):
        return "허용되지 않는 별명입니다."

0개의 댓글