파알못 파이썬: 3. 예외 처리

Table of Content

파이썬을 공부한 내용을 정리한 글입니다. 파알못이라 이상하거나 틀린 내용이 있을 수 있습니다…

기본적인 예외 처리

파이썬에서는 예외 처리를 위해 try, except, else, finally 블록을 사용합니다.

  • try 블록을 통해 에러를 캐치합니다.
  • except 블록은 try 블록에서 감지된 에러를 처리합니다.
  • else 블록은 에러가 발생하지 않았을 때 실행됩니다.
  • finally 블록은 에러 발생여부와 상관없이 무조건 실행됩니다. 주로 할당된 자원을 해제할 때 사용합니다.
try:
    file = open("app.py")
    age = int(input("Age: "))
except ValueError as ex:
    print("You didn't enter a valid age.")
    print(ex)
    print(type(ex))
else:
    print("No exceptions were thrown.")
finally:
    file.close()

print("Execution continues.")

다른 예외 처리

발생할 에러가 여러가지인 경우 except 블록을 여러 개 배치합니다.

try:
    age = int(input("Age: "))
    xfactor = 10 / age
except ValueError as ex:
    print("You didn't enter a valid age.")
except ZeroDivisionError:
    print("Age cannot be 0.")
else:
    print("No exceptions were thrown.")

print("Execution continues.")

그러나 except 블록이 너무 반복적이라고 판단되는 경우 expect 절 선언부에 2개 이상의 에러를 명시할 수 있습니다.

try:
    age = int(input("Age: "))
    xfactor = 10 / age
except (ValueError, ZeroDivisionError) as ex: # 2개 이상의 에러 명시
    print("You didn't enter a valid age.")
except ZeroDivisionError: # 이 블록은 실행되지 않음. 위의 블록에서 이미 ZeroDivisionError를 처리하기 때문
    print("Age cannot be 0.")
else:
    print("No exceptions were thrown.")

print("Execution continues.")

with 문

파일 객체를 사용할 때 할당받은 자원을 해제할 코드를 구현해줘야 합니다. 따라서 예외 처리를 할 때 try 블록에서 자원을 할당받은 후 finally 블록에서 자원을 해제하는 코드를 작성할 수 있습니다.

try:
    file = open("app.py")
finally:
    file.close()

with문을 사용하면 할당받은 자원을 해제할 코드를 작성할 필요가 없습니다.

try:
  with open("app.py") as file: # flie: open() 함수가 반환하는 파일 객체
      print("File opened.")

with문엔 여러 개의 자원 할당 코드를 작성할 수 있습니다.

try:
    with open("app.py") as file, open("another.txt") as target:
        print("File opened.")

강제로 에러 발생시키기

강제로 에러를 발생시키려면 raise 키워드를 사용합니다.

def calculate_xfactor(age):
    if age <= 0:
        raise ValueError("Age cannot be 0 or less.") # 에러 강제 발생
    return 10 / age

try:
    print(calculate_xfactor(-1)) # 에러 감지
except ValueError as error:
    print(error)

예외 처리는 무겁다.

예외를 처리하는 작업은 그렇지 않은 작업보다 무겁습니다. 이를 비교해보기 위해 예외를 처리하는 코드와 그렇지 않는 코드의 실행시간을 출력하는 코드를 돌려봤습니다.

from timeit import timeit

# 예외를 처리하는 코드
code1 = """
def calculate_xfactor(age):
    if age <= 0:
        raise ValueError("Age cannot be 0 or less.") # 예외 발생
    return 10 / age

try:
    print(calculate_xfactor(-1)) # 에러 발생
except ValueError as error:
    print(error)
"""

# 예외를 처리하지 않는 코드
code2 = """
def calculate_xfactor(age):
    if age <= 0:
        return None
    return 10 / age

xfactor = calculate_xfactor(-1)
if xfactor == None:
    pass
"""

print("Exception Code:", timeit(code1, number=100000))  # 10만 번 반복한 시간 반환
print("No Exception Code:", timeit(code2, number=100000))  # 10만 번 반복한 시간 반환

제 노트북으로 실행해본 결과 예외를 처리하는 코드가 그렇지 않은 코드보다 수십 배 더 느렸습니다.

Exception Code: 1.120521133
No Exception Code: 0.02664571700000007

이처럼 예외 처리는 무겁기 때문에 가급적 예외를 발생시키지 않는 것이 좋습니다. 예외 발생 시 bool 타입을 반환하는 메소드를 사용하거나 처음부터 무효한 데이터를 제외하는 것도 방법일 수 있겠습니다.

댓글 남기기