파이썬 개발자들은 어떤 함수를 작성할 때 반환값 None에 특별한 의미를 부여하는 경향이 있습니다. 예를들어 어떤 숫자를 다른 숫자로 나누는 헬퍼 함수를 생각해보면 0으로 나누는 경우에는 결과가 정의되어 있지 않기 때문에 None을 반환하는게 자연스럽습니다.

def devide (a,b):
    try:
        return a/b
    except ZeroDivisionError:
        return None
result = devide(x,y)
if result is None:
    print ("Invalid inputs")

위와 같이 코드를 해석할 수 있습니다. 


그런데 분자가 0이 되면 반환 값도 0이되어 버립니다. 그러면 if 문과 같은 조건에서 결과를 평가할 때 문제가 될 수 있습니다. 오류인지 알아보려고 None 대신 실수로 False에 해당하는 값을 검사할 수도 있습니다.

result = devide(0,5)
if result is None:
    print ("Invalid inputs") # 잘못

이 예는 None에 특별한 의미가 있을 때 파이썬 코드에서 흔히 발생하는 실수입니다.

이러한 오류가 발생하는 상황을 줄히는 방법은 두 가지 입니다.

1. 반환 값을 두 개로 나눠서 튜플로 담는 방법 

튜플의 첫 번째 부분은 작업이 성공했는지 실패했는지를 알려주고 두 번째 부분은 계산된 실제 결과를 반환하는 것입니다.

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

success, result = devide(x,y)
if not success:
print ("Invalid inputs")

이 코드의 문제는 호출자가 (파이썬에서 사용하지 않을 변수에 붙이는 관례인 밑줄 변수 이름을 사용해서) 튜플의 첫 번쨰 부분을 쉽게 무시할 수 있다는 점입니다.


_, result = devide(x,y)
if not result:
    print ("Invalid inputs")

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

def devide (a,b):
    try:
        return a/b
    except ZeroDivisionError as e:
        raise ValueError('Invalid inputs') from e

이제 호출하는 쪽에서 잘못된 입력에 대한 예외를 처리해야 합니다. 호출하는 쪽에서 더는 함수의 반환 값을 조건식으로 검사할 필요가 없습니다. 


x, y = 5,0
try:
    result = devide(x,y)
except ValueError as e:
    print(e)
else:
    print('Result is %.1f' % result)

요약

None을 반환하는 함수가 오류를 일으키기 쉬운 이유는 None이나 다른 값(예를 들면 0이나 빈 문자열)이 조건식에서 False로 평가되기 때문

None보다는 예외를 일으키는 것이 깔끔