[Python] Skill of coding - None말고 예외

Hyeseong·2020년 12월 9일
0

python skill of coding

목록 보기
6/18

None을 반환하지말고 예외를 일으키자

유틸리티 함수 작성 시 반환 값 None에 특별한 의미를 부여하는 경향이 있어요.
예를들어 어떤 숫자를 다른 숫자로 나누는 헬퍼 함수를 생각해보죠. 0으로 나누는 경우에는 결과가 정의되어 있지 않기 때문에 None을 반환하는게 자연스러워요.


def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return None

assert divide(4, 2) == 2
assert divide(0, 1) == 0
assert divide(3, 6) == 0.5
assert divide(1, 0) == None

이 함수를 사용하는 코드는 반환 값을 다음과 같이 해석해요

x, y = 1, 0
result = divide(x, y)
if result is None:
    print('Invalid inputs')
else:
    print('Result is %.1f' % result)
Invalid inputs

분자가 0이 되면 어떤 일이 일어날까? 반환 값도 0이 되어버려요.(분모가 0이 아닐 경우) 그러면 if 문과 같은 조건에서 결과를 평가 할 때 문제가 될 수 있어요. 오류인지 알아내려고 None대신 실수로 False에 해당하는 값을 검사 할 수도 있어요.

x, y = 0, 5
result = divide(x, y)

if not result: # result == 0
    print('Invalid inputs')  # This is wrong!
else:
    assert False
Invalid inputs

이 예는 None에 특별한 의미가 있을 때 파이썬 코드에서 흔히 하는 실수다. 바로 이 점이 함수에서 None을 반환하면 오류가 일어나기 쉬운 이유에요. 오류가 일어나는 상황을 줄이는 방법은 2가지에요.

첫 번째 방법은 반환 값을 2개로 나눠서 튜플에 담는것이에요. 튜플의 첫 번째 부분은 작업이 성공했는지 실패했는지를 알려줘요. 두 번째 부분은 계산된 실제 결과에요.

def divide(a, b):
    try:
        return True, a / b
    except ZeroDivisionError:
        return False, None

x, y = 5, 0
success, result = divide(x, y)
if not success:
    print('Invalid inputs')
Invalid inputs

이 함수를 호출하는 쪽에서는 튜플을 풀어야해요. 따라서 나눗셈의 결과만 얻을게 아니라 튜플에 들어 있는 상태 부분까지 고려하니깐요.

문제는 호출자가 튜플의 첫 번째 부분을 쉽게 무시할 수 있다는 점입니다. 얼핏 보기에는 이렇게 작성한 코드가 나빠 보지이 않아요. 하지만 결과는 그냥 None을 반환하는 것만큼이나 나빠요.

x, y = 5, 0
_, result = divide(x, y)
if not result:
    print('Invalid inputs')  # This is right

x, y = 0, 5
_, result = divide(x, y)
if not result:
    print('Invalid inputs')  # This is wrong
Invalid inputs
Invalid inputs

이런 오류를 줄이기에 더 좋은 두 번째 방법은 절대로 None을 반환하지 않는 것이에요 대신 호출하는 쪽에 예외를 일으켜서 호출하는 쪽에서 그 예외를 처리하게 하는 것입니다. 여기서는 호출하는 쪽에 입력값이 잘못됐음을 알리려고 ZeroDivision을 ValueError로 변경했어요.


def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as e:
        raise ValueError('Invalid inputs') from e
    
x, y = 5, 2
try:
    result = divide(x, y)
except ValueError:
Result is 2.5

이제 호출하는 쪽에서는 잘못된 입력에 대한 예외를 처리해야해요. 호출하는 쪽에서는 더는 함수의 반환 값을 조건식으로 검사할 필요가 없어요. 함수가 예외를 일으키지 않았다면 반환값은 문제가 없어요. 예외를 처리하는 코드도 깔끔해지고요.

핵심정리

  • 특별한 의미를 나타내려고 None을 반환하는 함수가 오류를 일으키기 쉬운 이유는 None이나 다른값(예. 0또는 빈 문자열)이 조건식에서 False로 평가되기 때문이에요.
  • 특별한 상황을 알릴 때 None을 반환하는 대신 예외를 일으키세요. 문서화가 되어 있다면 호출하는 코드에서 예외를 적절하게 처리할 것이라고 기대할 수 있어요.
profile
어제보다 오늘 그리고 오늘 보다 내일...

0개의 댓글