알고리즘 문제를 풀다보면 종종 try except를 쓰고 싶은 유혹에 넘어가게 된다. 파이썬으로 알고리즘 문제를 풀담보면 파이썬이 추구하는 EAFP 스타일 ("it's easier to ask for forgiveness than permission")에 맞춰서 코딩을 하게된다. 앞뒤 고려하지 않고 try except를 걸어버리니 굉장히 편하지만, 마음이 썩 편하지는 않다. 오늘은 그 안일한 생각으로 저지른 치명적인 실수에 대해서 얘기해보려 한다.
인덱싱 에러만 고려할 때, 과연 우리는 if문을 사용할 필요가 있을까? if문을 사용할 경우 CPU 명령 및 분기(Branch) 예측에 비용이 발생하게 된다. Error가 발생할 확률이 매우 높은 경우가 아니라면 try문을 사용하는 것이 최적화하기엔 유리하다. 하지만 if문을 통해 케이스를 명확하게 보여줘야 하는 경우도 있어 상황에 맞춰서 적절하게 사용해야 한다.
>>> import timeit
>>> timeit.timeit(setup="a=1;b=1", stmt="a/b") # no error checking
0.06379691968322732
>>> timeit.timeit(setup="a=1;b=1", stmt="try:\n a/b\nexcept ZeroDivisionError:\n pass")
0.0829463709378615
>>> timeit.timeit(setup="a=1;b=0", stmt="try:\n a/b\nexcept ZeroDivisionError:\n pass")
0.5070195056614466
>>> timeit.timeit(setup="a=1;b=1", stmt="if b!=0:\n a/b")
0.11940114974277094
>>> timeit.timeit(setup="a=1;b=0", stmt="if b!=0:\n a/b")
0.051202772912802175
try except로 index error 케이스를 다뤘고 분명 로직에 문제가 없어 보였지만 출력 값이 이상했다. 파이썬에서의 인덱싱 개념을 간과하고 다른 언어의 인덱싱 시스템에 익숙해져 저지른 실수다. 여타 다른 언어와 달리 python에서는 음수의 인덱스는 Index Error를 raise하지 않는다. 음수인 인덱스 값을 마주했을 때는 Index Error를 raise해 except문을 타도록 코드를 작성해 실수했다. 아래 코드에서는 i의 값이 10 ~ 19일 때 Index Error를 출력한다. 하지만 음수의 경우 except문을 타지 않고 그대로 값을 출력하는 것을 볼 수 있다.
num_list = list(range(10))
for i in range(-10, 10):
try:
print("Print index!", num_list[i])
except:
print("Index Error!", i)