본문 바로가기

Data_Analysis_Track_33/Python

Python_07(예외처리)

오류 : 함수나 메소드가 처리 도중 다음 명령문을 실행할 수 없는 상황
오류 중 처리가능한 것을 Exception(예외) 라고 한다. 그리고 그 예외를 처리하는 것을 Exception Handling 이라고 한다.

오류의 종류
1. 파이썬 문법을 어겨서 발생하는 오류
- 코드 상 100% 발생하는 오류
- 코드를 수정해야 한다.
- 보통 이런 오류는 컴파일 방식 언어의 경우 컴파일 때 에러를 내서 수정하도록 한다.(Python은 해당되지 않는다.)
2. 실행 환경의 문제로 발생하는 오류
- 코드상에서는 Exception의 발생여부를 확신할 수 없다.
- 만약 발생할 경우 어떻게 처리할지를 구현해야 한다.

1. 예외처리 -> 2. 예외 발생 -> 3. 사용자 정의 예외 class 생성

예외처리(Exception handling) : try, except 구문 (try, except, finally, else가 있지만 else는 잘 쓰지 않는다.)

# try, except 구문
try:
    Exception 발생가능한 코드 블록  # try block
except [Exception클래스 이름 [as 변수]] :
    처리 코드         # except block



try block : Exception 발생 가능한 코드와 그 코드와 연결된 코드들을 블록으로 묶는다.
- 연결된 코드 : Exception이 발생 하지 않았을 때 실행되는 코드


except block : 발생한 Exception을 처리하는 코드 블록 작성
- try block 먼저 실행하다가 exception 발생시에만 except block 실행
- 모든 exception을 처리하는 경우 except: 선언
- 특정 exception을 처리하는 경우 except Exception클래스 이름: 선언
모든 Exception들은 클래스로 정의 되어 있다. 그 클래스 이름을 적어준다.
Exception들을 각각 처리할 수 있으며 이 경우 except 구문(처리구문)을 연속해서 작성하면 된다.

 

print('프로그램 시작') # 1

try:
    num = int(input('정수:')) # 2 Exception 발생 가능성이 있는 코드. (ex. 문자열 입력 -> ValueError)
    result = 10 // num        # 3 Exception 발생 가능성이 있는 코드. (ex. 0 입력 -> ZeroDivisionError)
    print('결과:',result)     # 4

except:
    print('실행도중 문제가 발생했습니다. 일단 처리했습니다.')  # EH(Exception Handling)
    
print('프로그램 종료')    # 5

# 정상흐름 : 1, 2, 3, 4, 5
# 2번에 Exception 발생 : 1, 2(Exception 발생 -> x), 3(x), 4(x), EH, 5
#                       -> 1, EH, 5
# 3번에 Exception 발생 : 1, 2, 3(Exception 발생 -> x), 4(x), EH, 5
#                       -> 1, 2, EH, 5
# Exception이 발생할 수 있는 구간이 여러개다 -> Exception 종류별로 따로 처리해야함.

 

# Exception 종류별로 따로 처리.
print('프로그램 시작') # 1

try:
    num = int(input('정수:')) # 2 Exception 발생 가능성이 있는 코드. ex) 문자열 입력
    result = 10 // num        # 3 Exception 발생 가능성이 있는 코드. ex) 0 입력
    print('결과:',result)     # 4
    # print('결과2',result2) NameError 발생코드
    print(1 + "1")  # TypeError 발생코드
    
except ValueError as ve: # ValueError를 처리하는 block
    print('정수로 변환하지 못했습니다. ValueError 발생')       # EH1
    print('ve 변수출력 : ', ve)
except ZeroDivisionError as ze: # ZeroDivisionError 를 처리하는 block
    print('0으로는 못나눕니다. ZeroDivisionError')             # EH2
    print('ze 변수출력 : ', ze)
except Exception as e: # 위의 두 Exception을 제외한 나머지 Exception을 처리.
    print('실행도중 문제가 발생했습니다. 일단 처리했습니다.')  # EH3
    print('e 변수출력 : ', e)
    
print('프로그램 종료')    # 5
# try에서 ValueError 발생 (2) : 1, EH1, 5
# try에서 ZeroDivisionError 발생(3) : 1, 2, EH2, 5
# try에서 ValueError, ZeroDivisionError를 제외한 exception발생(NameError) : 1, 2, 3, 4, EH3, 5


finally 구문 : 예외 발생여부, 처리 여부와 관계없이 무조건 실행되는 코드블록(무조건 실행)
- try 구문에 반드시 실행되야 하는 코드블록을 작성할때 사용한다. (입출력 관련해서 사용)
구문순서
1. try - except - finally
2. try - except
3. try - finally

 

print('시작')
try:
    print(1)
    a = 10 / 2
    print(2)
    b = int('ab') # -> ValueError 발생
except ValueError:
    print(3)

finally:
    print('무조건실행할코드') # 오류가 발생해도 무조건 실행
    
print('종료')

 

try:
    a = int(input())
        
except:
    print('예외발생')
    
else:
    print(a + 10) # except: 과 finally: 사이에 else: -> except이 나지 않는다면 else block 코드 실행
                  # 보통 else:는 쓰지 않고 else block에 넣을 코드들을 try block에 모두 넣는다.
    
finally:
    print('무조건 실행할 코드')


Exception 발생 시키기(사용자 정의 Exception 클래스 구현)
- Exception 클래스를 상속받는다.
- 클래스 이름은 Exception 상황을 설명할 수 있는 이름을 준다.

 

# 월에 1 ~ 12 이외의 값을 대입할 때 발생시킬 Exception 클래스 정의
class InvaildMonthException(Exception):
    
    def __init__(self, invalid_month):
        # attribute로 입력된 "잘못된 월" 값을 저장.
        self.invalid_month = invalid_month
        
    def __str__(self):
        # Exception 메세지를 문자열로 반환.
        return f"{self.invalid_month}는 사용할 수 없는 월입니다. 1 ~ 12월 만 가능합니다."


raise : Exception을 강제로 발생시킨다.
구문 : raise Exception객체

 

def use_month(month):
    if month < 1 or month > 12:
        # 처리할 수 없는 월. 호출한 곳으로 돌아간다. -> 비정상(예외발생)종료상태로 돌아간다.
        raise InvaildMonthException(month) # 비정상 return
    else:
        print('month : ', month) # 사용

 

# day와 year는 있다고 가정
use_month(5) # 1. 월사용
print('use_day(30)') # 2. 일 사용
print('use_year(2020)') # 3. 년도를 사용

 

print('시작') # 1
try:
    use_month(50) # 2. Exception 발생 가능성이 있는 코드 : 처리할 수 없는 월 입력, 에러 발생 -> 에러코드 : InvaildMonthException 출력
    print('use_day(30)') # 2. 일 사용
    print('use_year(2020)') # 3. 년도를 사용
except InvaildMonthException as e: # e에는 raise한 Exception 객체가 할당.
    print('예외 처리함', e) # e -> InvaildMonthException 클래스의 return 값
    print(e.invalid_month)
    
print('종료') # 5