None을 반환하기보다는 예외를 발생키셔라

Minsang Yu·2023년 8월 15일
0

파이썬 개발자 들은 유틸리티 함수를 작성할 때 반환 값을 None으로 하면서 이 값에 특별한 의미를 부여하려는 경향을 보인다.
경우에 따라서는 이 결정이 타당할 수 있다.

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

x, y = 1, 0
result = careful_dvide(x,y)
if reuslt is None:
	print('잘못된 입력')
   

0으로 나누는 경우 결과가 정해져 있지 않으므로 None을 반환하는것이 타당해 보인다.

하지만 함수로 반환한 결과를 if 문 등의 조건문으로 검사할 때 0 값이 문제가 될 수 있다. None 인지 검사하는 대신 실수로 빈 값을 False로 취급하는 검사를 실행할 수 있다.

x, y = 0, 5
resut = careful_divide(x, y)
if not result:
	print('질못된 입력') # 이 코드가 실행되는데 사실 이 코드가 실행되면 안된다.

분자가 0이 되면 반환값도 0이 되버린다. if 문으로 None을 검사하려고 했는데 실수로 False를 검사하는 경우도 있다.

해결책은 2가지가 있다.

1. 반환값을 두개로 분리해 튜플에 담는 방법.

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

이 함수를 호출하는 쪽에서 튜플을 언패킹해야한다. 이로 인해 나눗셈 결과를 그냥 검사하지 못하고 항상 튜플에서 상태 부븐을 살펴보게 된다.

success, result = careful_divide(x, y)
if not success:
	print('잘못된 입력')

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

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

이런 실수를 줄일 수 있는 더 나은 방법은 특별한 경우에 결코 None을 반환하지 않는것이다. 대신 Exception을 호출한 쪽으로 발생시켜서 호출 자가 이를 처리하게 한다.

다음 코드는 ZeroDivisionError 가 발생한 경우 이를 ValueError로 던져서 호출한 쪽에 입력값이 잘못됐음을 알리는 경우다.

def careful_divide(a, b):
	try:
    	return a / b
    except ZeroDivisionError as e:
    	raise ValueError('잘못된 입력')

호출자는 더이상 반환 값에 대한 조건문을 사용하지 않아도 된다. 대신 반환값이 항상 올바르다고 가정하고 try else블록에서 이 값을 즉시 사용할 수있다.

x, y = 5, 2
try:
	result = a / b
except ValueError:
	print('잘못된 입력')
else:
	print('결과는 %.1f 입니다.' % result)
    
 >>>
 결과는 2.5 입니다.

정리

  • 특별한 의미를 표시하는 None을 반환하는 함수를 사용하면 None과 다른값 (0이나 빈 문자열)이 조건문에서 False로 평가될 수 있기 떄문에 실수하기 쉽다.
  • 특별한 상황을 표현하기 위해 None을 반환하는 대신 예외를 발생시켜라 문서에 예외정보를 기록해 호출자가 예외를 제대로 처리하도록 하라
  • 함수가 특별한 경우를 포함하는 그 어던 경우에도 절대로 None을 반환하지 않는다는 사실을 타입 애너테이션을 통해서 명시할 수 있다.
profile
Jr. DataEngineer

1개의 댓글

comment-user-thumbnail
2023년 8월 15일

즐겁게 읽었습니다. 유용한 정보 감사합니다.

답글 달기