[Python] 에러와 예외 처리 기초
프로그램 실행 중 발생할 수 있는 다양한 예외 상황을 적절히 처리하는 것은 안정적인 프로그램 작성의 핵심이다.
예외 처리의 기본부터 실전 패턴까지 알아보자.
try-except 구문
기본 구조
# 기본적인 예외 처리
try:
number = int(input("숫자를 입력하세요: "))
result = 10 / number
print(result)
except ValueError:
print("올바른 숫자를 입력하세요")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다")
except: # 모든 예외 처리 (권장하지 않음)
print("알 수 없는 에러가 발생했습니다")
try-except-else-finally
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("파일을 찾을 수 없습니다")
else:
print("파일 읽기 성공:", content)
finally:
file.close() # 예외 발생 여부와 관계없이 실행
자주 발생하는 예외
1. TypeError
# 타입 불일치
def add_numbers(a, b):
try:
return a + b
except TypeError:
print("숫자만 더할 수 있습니다")
return None
result = add_numbers("hello", 5) # TypeError 발생
2. ValueError
# 부적절한 값
def get_positive_number():
try:
num = int(input("양수를 입력하세요: "))
if num <= 0:
raise ValueError("양수가 아닙니다")
return num
except ValueError as e:
print(f"에러: {e}")
return None
3. IndexError/KeyError
# 리스트와 딕셔너리 접근 에러
def safe_access():
my_list = [1, 2, 3]
my_dict = {"a": 1, "b": 2}
try:
value1 = my_list[5] # IndexError
value2 = my_dict["c"] # KeyError
except IndexError:
print("리스트 인덱스가 범위를 벗어났습니다")
except KeyError:
print("존재하지 않는 키입니다")
예외 처리 패턴
1. EAFP (Easier to Ask for Forgiveness than Permission)
# Python 스타일의 예외 처리
# EAFP 방식
def get_dict_value(dictionary, key):
try:
return dictionary[key]
except KeyError:
return None
# LBYL 방식 (비Python스러움)
def get_dict_value_lbyl(dictionary, key):
if key in dictionary:
return dictionary[key]
else:
return None
2. 예외 연쇄
def process_data(data):
try:
processed = some_processing(data)
except Exception as e:
raise RuntimeError("데이터 처리 실패") from e
3. 컨텍스트 관리자
class FileManager:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'r')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
# 사용
with FileManager('data.txt') as file:
content = file.read()
커스텀 예외
기본 커스텀 예외
class CustomError(Exception):
"""기본 커스텀 예외"""
pass
def validate_age(age):
if age < 0:
raise CustomError("나이는 음수일 수 없습니다")
상세 커스텀 예외
class ValidationError(Exception):
def __init__(self, message, value):
self.message = message
self.value = value
super().__init__(self.message)
class DatabaseError(Exception):
def __init__(self, message, query):
self.message = message
self.query = query
super().__init__(self.message)
# 사용 예시
def process_user_input(value):
try:
if not isinstance(value, (int, float)):
raise ValidationError("숫자만 입력 가능합니다", value)
# 처리 로직
except ValidationError as e:
print(f"검증 오류: {e.message}, 입력값: {e.value}")
실전 예외 처리 패턴
1. 재시도 패턴
import time
def retry_operation(func, max_attempts=3, delay=1):
"""작업 실패 시 재시도하는 데코레이터"""
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
if attempts == max_attempts:
raise e
time.sleep(delay)
return wrapper
@retry_operation
def unstable_network_call():
# 네트워크 요청 시뮬레이션
import random
if random.random() < 0.7:
raise ConnectionError("네트워크 오류")
return "성공"
2. 로깅과 예외 처리
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def divide_numbers(a, b):
try:
result = a / b
logger.info(f"나눗셈 성공: {a} / {b} = {result}")
return result
except ZeroDivisionError:
logger.error(f"0으로 나누기 시도: {a} / {b}")
raise
except TypeError as e:
logger.error(f"타입 에러: {e}")
raise
예외 처리 팁
- 구체적인 예외 처리
# 나쁜 예 try: # 코드 pass except Exception: pass # 좋은 예 try: # 코드 pass except ValueError: # ValueError 처리 pass except TypeError: # TypeError 처리 pass
- 구체적인 예외 처리
try:
raise ValueError("잘못된 값")
except ValueError as e:
print(f"에러 메시지: {str(e)}")
print(f"에러 타입: {type(e).__name__}")
'개발&프로그래밍' 카테고리의 다른 글
[Python] if문과 조건문 (0) | 2024.11.26 |
---|---|
[Python] for문과 while문 실전 활용 (0) | 2024.11.23 |
[python] 함수 작성법과 활용 (1) | 2024.11.21 |
[python] 파일 입출력 기초 가이드 (1) | 2024.11.20 |
[python] 리스트와 딕셔너리 완벽 이해하기 (0) | 2024.11.20 |
댓글