어제 퇴근 후에 간단한 기술 면접이 있었는데 질문중에 예외처리 문법에서 else의 역할이 무엇인지에 대한 질문이 있었다.
항상 except까지만 사용하다보니 정확하게 답변을 못했는데 파이썬의 예외처리 문법 관련해서 다시 한번 살펴볼 계기로 아주 적절한 계기같다. 근데 단순하게 예외처리에서 사용되는 키워드의 역할 정도만 정확하게 파악해보려고 공식 문서 살펴봤는데 당연하겠지만 예외처리를 구성하는 문법이 꽤나 다양해서 전체적으로 정리해보려고 한다.
파이썬의 예외처리
파이썬의 예외처리 문법에서 직접적으로 사용되는 키워드는 try, except, else, finally의 4종류가 사용된다.
각 키워드의 역할을 간단하게 정리하면 다음과 같다.
- try : 예외 발생을 잡아낼 코드의 부분을 지정하는 키워드이다. try 밖에서 발생한 예외는 이후 지정된 예외 케이스와 같더라도 지정된 예외 처리 로직을 수행하지 않는다. 당연하지만 필수로 사용해야 하는 키워드
- except <EXCEPT_CASE / ERROR_CASE> : try 키워드로 감싸진 코드에서 발생할 수 있는 예외나 에러의 케이스를 직접 지정하고 그 예외가 발생했을 때 수행할 코드를 지정해줄 수 있다. 필수로 사용해야 하는 키워드
- else : try로 지정한 코드에서 어떤 예외도 발생하지 않았을 경우 수행할 코드를 지정해줄 수 있다. 사용 여부는 선택할 수 있는 키워드이다.
- finally : except, else 작동 여부에 상관없이 무조건 작동해야 하는 코드를 지정해줄 수 있다. 사용 여부를 선택할 수 있는 키워드이다.
각 키워드를 사용한 간단한 예제 코드를 만들어보고 각각의 동작을 확인해보면 쉽게 이해할 수 있다.
# Exception Handling Test
test_list = [ i for i in range(10) ]
input_data = int(input('인덱스 선택 : '))
try:
print('선택한 인덱스의 데이터 : {}'.format(test_list[input_data]))
except IndexError:
print('Index out of range CHECK')
except ValueError:
print('Only use integer data types')
else:
print('Good. No exception')
finally:
print('Exception Handling Test done')
숫자들로 이루어진 리스트를 생성해서 입력받은 숫자를 인덱스로 사용하여 출력하는 테스트코드이다.
사실 raise를 사용하면 번거로운 과정 없이 예외를 발생시킬 수도 있긴하다.
어쨋든 이 코드에서 발생 가능한 예외는 두가지정도가 있다. 첫번째는 입력시에 정수가 아닌 문자가 입력되는 경우, 두번째는 입력한 숫자가 리스트의 길이를 넘어서는 경우가 있다.
먼저 의도한 데이터 타입과 다른 데이터가 입력되었을 경우의 실행 결과는 다음과 같다.
ValueError 예외 발생에 대한 코드가 있지만 해당 예외의 발생 위치가 try절이 아니기때문에 finally 코드를 포함한 지정된 예외 처리 코드가 작동하지 않은 것을 확인 할 수 있다.
다음으로 입력한 숫자가 리스트의 길이를 넘어서는 경우의 실행 결과는 다음과 같다.
발생한 예외는 IndexError로 예외처리 조건에 등록되어 있는 에러가 발생하였기 때문에 작성된 문자열이 출력되었고 마지막으로 finally에 지정해둔 문자열도 출력된 것을 확인 할 수 있다.
만약 아무 예외도 발생하지 않았을 경우의 실행 결과는 다음과 같다.
발생한 예외가 없기때문에 else에 지정해둔 문자열이 출력되었고, finally에 지정한 문자열이 마지막으로 출력되었다.
공식문서에 따르면 else 키워드를 사용하는 것이 코드 안정성을 높히는 방향이라고 한다. try - except 절로 보호되는 코드에서 발생한 예외가 아닌 다른 부분에서 발생하는 예외마저도 잡아낼 수 있는 가능성이 존재한다고하니 else 키워드까지 사용하는 버릇을 들이도록 신경쓰는 것이 좋을 것 같다.
finally 키워드의 경우에도 사용하지 않아도 상관은 없겠으나, 지금까지의 경험에 비추어보면 API의 작동 결과를 최종적으로 로그로 남기는 코드를 finally절에 지정해놓으면 좋을 것 같다는 생각이 든다. 한번 해볼 가치는 충분한듯
사용자 정의 예외
파이썬도 당연하게도 사용자가 직접 정의한 예외를 사용할 수 있다.
사용자 정의 예외를 정의할 때에는 Exception 클래스를 상속하는 방법이 사용된다.
# User Custom Error Test
class UserCustomError(Exception):
def __init__(self):
super().__init__('User Custom Error are raised')
test_list = [ i for i in range(10) ]
input_data = int(input('인덱스 선택 : '))
try:
if input_data == 5:
raise UserCustomError
print('입력한 인덱스의 데이터 : {}'.format(test_list[input_data]))
except Exception as e:
print('Exception is occured :: ', e)
except IndexError:
print('Index out of range CHECK')
else:
print('Good. No exception')
finally:
print('Exception Handling Test done')
방금까지 사용했던 테스트 코드에 사용자 정의 예외를 위한 코드를 추가해보았다. 먼저 사용자 정의 예외를 클래스 형태로 선언해주어야한다. 해당 클래스는 단순하게 지정한 문자열을 출력하도록 작성해두었다. 그리고 try절에서 입력받은 인덱스 값이 5일 경우에 사용자 정의 예외를 발생시키는 코드를 추가해두었다. 위 코드의 작동 결과는 다음과 같다.
좀 더 복잡한 동작을 작성해 둘 수 있을 것 같은데 예외 발생시에 어떤식으로 데이터를 넘겨 받을 수 있는지 확인해보면 시스템의 특성과 상황에 맞는 사용자 정의 예외를 생성하고 사용할 수 있을 것 같다.
결론
- 예외 처리를 구성하는 키워드 중 필수로 사용해야 하는 부분은 try와 except이지만 선택 사항에 해당되는 else, finally 키워드도 가능한 같이 구성하는 것이 더 안정적인 코드라고 할 수 있다.
- 안정성 확보의 목적이 아니더라도 각 키워드를 전부 구성하는 것이 가독성 부분에서도 긍정적인 효과를 가질 수 있을 것 같다.
- 파이썬이 문서화가 참 잘되어있는것 같다~
참고
'프로그래밍 > Python' 카테고리의 다른 글
Django - Admin(Search, Filtering) (0) | 2022.02.04 |
---|---|
DRF - Serializer (0) | 2021.12.22 |
Django - Redis 캐싱 (0) | 2021.09.27 |
Django - 로깅 (0) | 2021.09.11 |
Conda 기본 (0) | 2020.07.29 |