키워드로 인수를 넘기는 방법은 파이썬 함수의 강력한 기능이에요.
키워드 인수의 유연성 덕분에 쓰임새가 분명하게 코드를 작성 할 수 있어요.
예. 어떤 숫자를 다른 숫자로 나눈다고 하자. 이 경우 특별한 경우에 주의해야 한다. 때로는 ZeroDivisionError 예외를 무시하고 무한대 값을 반환하고 싶을 수 있다. 어떨 때는 OverflowError 예외를 무시하고 0을 반환하고 싶을 수 있다.
def safe_division(number, divisor, ignore_overflow,
ignore_zero_division):
try:
return number / divisor
except OverflowError:
if ignore_overflow:
return 0
else:
raise
except ZeroDivisionError:
이 함수를 사용하는 방법은 심플하다. 다음 한수 호출은 나눗셈에서 일어나는 float 오버플로우를 무시하고 0을 반환한다.
result = safe_division(1.0, 10**500, True, False)
print(result)
assert result is 0
0
다음 함수 호출은 0으로 나누면서 일어나는 오류를 무시하고 무한대 값을 반환한다.
result = safe_division(1,0,False, True)
print(result)
inf
문제는 예외 무시 동작을 제어하는 두 불 인수의 위치를 혼동하기 쉽다는 점이다. 이 때문에 찾기 어려운 버그가 쉬이 발생할 수 있다. 이런 코드의 가능성을 높이는 한 가지 방법은 키워드 인수를 사용하는 것이다. 다음과 같이 함수가 기본적으로 매우 주의 깊고 항상 예외를 다시 일으키게 만들 수 있다.
except ZeroDivisionError:
if ignore_zero_division:
return float('inf')
else:
raise
그러면 호출하는 쪽에서 키워드 인수로 특정 연산에는 기본 동작을 덮어쓰고 무시할 플래그를 지정할 수 있다.
assert safe_division_b(1.0, 10**500, ignore_overflow=True) is 0
assert safe_division_b(1.0, 0, ignore_zero_division=True) == float('inf')
문제는 이런 키워드 인수가 선택적인 동작이라서 함수를 호출하는 쪽에 키워드 인수로 의도를 명확하게 드러내라고 강요할 방법이 없다는 점이다. safe_division_b라는 새 함수를 정의한다고 해도 여전히 위치 인수를 사용하는 이전 방식으로 호출할 수 있다.
safe_division(1, 10**500, True, False)
0.0
이처럼 복잡한 함수를 작성할 때는 호출하는 쪽에서 의도를 명확히 드러내도록 요구하는 게 낫다. 키워드 전용 인수로 함수를 정의해서 의도를 명확히 드러내도록 요구할 수 있다. 키워드 전용 인수는 키워드로만 넘길 뿐, 위치로는 절대 넘길 수 없다.
다음은 키워드 전용 인수로 safe_division 함수를 다시 정의한 버전이다. 인수 리스트에 있는 * 기호는 위치 인수의 끝과 키워드 전용 인수의 시작을 가리킨다.
def safe_division_c(number, divisor, * , ignore_overflow=False, ignore_zero_division=False):
pass
이제 키워드 인수가 아닌 위치 인수를 사용하는 함수 호출은 동작 하지 않는다.
safe_division_c(1, 10**500, True, False)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-162-2f9b657427b5> in <module>
----> 1 safe_division_c(1, 10**500, True, False)
TypeError: safe_division_c() takes 2 positional arguments but 4 were given
키워드 인수와 그 기본값은 기대한 대로 동작한다.
safe_division_c(1.0, 0, ignore_zero_division=True) # No exception
try:
safe_division_c(1.0, 0)
except ZeroDivisionError:
pass # Expected