프로그래밍을 하다 보면 예상치 못한 오류나 예외 상황을 마주할 때가 많습니다. 이러한 오류를 적절히 처리하지 않으면 프로그램이 갑작스럽게 중단되거나, 원하지 않는 동작을 할 수 있습니다. 파이썬은 이런 상황을 관리하기 위해 강력한 예외 처리 메커니즘을 제공합니다. 이번 포스팅에서는 파이썬의 예외 처리 방법에 대해 실무 예제를 통해 자세히 알아보겠습니다
그 외에 파이썬의 연사자 와 함수 에 대해 궁금하시면 아래 포스팅을 같이 참고해주세요
✅ 연산자 문법 정리
[ 파이썬 ] 비교 연산자 문법 정리 ( ==, !=, >, <, >=, <= ) 및 예제
[파이썬] 산술 연산자 문법 정리 ( + , - , * , / , % , **, // ) 및 예제
[ 파이썬 ] 논리 연산자 문법 정리 ( AND,OR,NOT ) 및 예제
[ 파이썬 ] 할당 연산자 문법 정리 ( =,+=,-=,/=,//=,%=,*=,**= ) 및 예제
✅ 함수 문법 정리
[ 파이썬 ] len() 함수 사용법 및 실제 프로젝트 예제
[ 파이썬 ] join() 함수 사용법 및 실제 프로젝트 예제
✅ 개념 정리
# 1. 파이썬 예외 처리의 기본 개념
예외(Exception)란 무엇인가?
예외는 프로그램 실행 중에 발생하는 예상치 못한 상황이나 오류를 말합니다. 예를 들어, 숫자를 0으로 나누려고 하거나, 존재하지 않는 파일을 열려고 할 때 발생하는 오류가 바로 예외입니다. 이러한 예외가 발생하면 프로그램은 기본적으로 즉시 중단되지만, 예외 처리를 통해 프로그램이 중단되지 않고 안정적으로 실행될 수 있도록 할 수 있습니다.
프로그램 실행 중 발생할 수 있는 다양한 오류 유형
파이썬에서는 ZeroDivisionError, ValueError, FileNotFoundError 등 다양한 내장 예외 유형을 제공합니다. 각 예외는 특정한 오류 상황에 대해 정의되어 있으며, 이러한 예외들을 적절히 처리하는 것이 중요합니다.
# 2.try-except 구조
try-except 구조는 파이썬에서 가장 기본적인 예외 처리 방법입니다. try 블록 안에는 예외가 발생할 수 있는 코드를 작성하고, except 블록에서는 예외가 발생했을 때 실행할 코드를 작성합니다.
try-except 구조 예시
try:
# 예외가 발생할 가능성이 있는 코드
x = 10 / 0
except ZeroDivisionError:
# 예외가 발생했을 때 실행되는 코드
print("0으로 나눌 수 없습니다.")
위 코드에서 0으로 나누기를 시도하면 ZeroDivisionError 예외가 발생하고, 프로그램은 중단되지 않고 except 블록이 실행됩니다.
그렇다면 실무에서는 어떤 식으로 쓰이는지 같이 살펴보도록 하겠습니다.
실무 예제 1: 사용자 입력 처리
🚩 사용자 입력 처리 🚩
try:
num = int(input("숫자를 입력하세요: "))
result = 100 / num
print(f"결과: {result}")
except ValueError:
print("유효한 숫자를 입력하세요.")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
위 코드에서 ValueError와 ZeroDivisionError를 각각 처리하여, 사용자가 잘못된 입력을 했을 때도 프로그램이 종료되지 않고 안내 메시지를 출력하도록 합니다.
실무 예제 2: 파일 읽기
🚩 파일 읽기 🚩
파일을 읽는 작업은 파일이 존재하지 않거나 접근 권한이 없는 경우 예외가 발생할 수 있습니다. 이를 try-except 구조로 처리해보겠습니다.
try:
with open('data.txt', 'r') as file:
content = file.read()
print(content)
except FileNotFoundError:
print("파일을 찾을 수 없습니다.")
위 코드에서는 FileNotFoundError 예외가 발생할 때 사용자에게 파일이 존재하지 않음을 알려줍니다.
# 3.다양한 예외 처리 방법
여러 예외를 처리하는 방법
실무에서는 여러 종류의 예외를 처리해야 하는 상황이 자주 발생합니다. 이를 위해 각 예외에 대해 개별적으로 except 블록을 작성하거나, 포괄적으로 처리할 수 있습니다.
실무 예제: 데이터베이스 연결 및 쿼리 실행
🚩 데이터베이스 연결 및 쿼리 실행 🚩
데이터베이스와의 연결 작업은 네트워크 상태나 데이터베이스 서버의 상태에 따라 다양한 예외가 발생할 수 있습니다.
try:
connection = db.connect("database_url")
result = connection.execute("SELECT * FROM users")
except ConnectionError:
print("데이터베이스에 연결할 수 없습니다.")
except TimeoutError:
print("쿼리 실행 시간이 초과되었습니다.")
except OperationalError as e:
print(f"데이터베이스 작업 중 오류가 발생했습니다: {e}")
여기서는 ConnectionError, TimeoutError, OperationalError 등을 개별적으로 처리하여, 각각의 상황에 맞는 에러 메시지를 출력합니다.
모든 예외를 포괄하는 방법
때로는 발생할 수 있는 모든 예외를 포괄적으로 처리해야 할 때가 있습니다. 이때는 except Exception as e를 사용하여 모든 예외를 한 번에 처리할 수 있습니다.
실무 예제: 외부 API 호출
🚩 외부 API 호출 🚩
외부 API를 호출하는 작업에서 다양한 예외가 발생할 수 있습니다. 예를 들어 네트워크 문제, 서버 오류 등이 있을 수 있습니다.
try:
response = requests.get("https://api.example.com/data")
data = response.json()
except Exception as e:
print(f"API 호출 중 오류가 발생했습니다: {e}")
이 코드에서는 모든 예외를 포괄하여 처리하되, 발생한 예외 메시지를 출력하여 문제를 파악할 수 있도록 합니다.
# 4. else와 finally 블록 사용
try-except 구조에 else와 finally 블록을 추가하면 예외 처리의 유연성을 높일 수 있습니다.
else 블록
else 블록은 try 블록에서 예외가 발생하지 않았을 때 실행됩니다. 예외가 발생하지 않은 경우에만 특정 작업을 수행하고 싶을 때 유용합니다.
실무예시 : 파일 처리 후 데이터 파싱
🚩 파일 처리 후 데이터 파싱 🚩
파일을 성공적으로 읽은 후, 데이터를 파싱하는 작업을 else 블록에서 수행할 수 있습니다.
try:
with open('data.txt', 'r') as file:
content = file.read()
except FileNotFoundError:
print("파일을 찾을 수 없습니다.")
else:
parsed_data = parse_data(content)
print("데이터 파싱이 성공적으로 완료되었습니다.")
이 코드는 파일을 읽는 데 문제가 없을 경우에만 데이터를 파싱하는 로직을 수행합니다.
finally 블록
finally 블록은 예외 발생 여부와 관계없이 항상 실행되는 코드를 작성할 때 사용합니다. 자원 해제나 정리 작업 등에 주로 사용됩니다.
실무 예제: 데이터베이스 연결 종료
🚩데이터베이스 연결 종료 🚩
데이터베이스 연결을 종료할 때 finally 블록을 사용하여 항상 연결을 종료하도록 할 수 있습니다.
try:
connection = db.connect("database_url")
result = connection.execute("SELECT * FROM users")
except Exception as e:
print(f"오류가 발생했습니다: {e}")
finally:
connection.close()
print("데이터베이스 연결이 종료되었습니다.")
이 코드에서는 예외가 발생하더라도 항상 finally 블록에서 데이터베이스 연결을 종료하도록 합니다.
# 5. 사용자 정의 예외 처리
사용자 정의 예외 클래스 만들기
특정한 상황에서 발생하는 사용자 정의 예외를 만들어서, 더 의미 있는 예외 처리를 할 수 있습니다.
실무 예제
🚩데이터베이스 연결 종료 🚩
나이를 입력받아 특정 조건에서 예외를 발생시키는 사용자 정의 예외를 만들어보겠습니다.
class InvalidAgeError(Exception):
def __init__(self, age, message="유효하지 않은 나이입니다."):
self.age = age
self.message = message
super().__init__(self.message)
def check_age(age):
if age < 0:
raise InvalidAgeError(age)
elif age < 18:
print("미성년자입니다.")
else:
print("성인입니다.")
try:
check_age(-5)
except InvalidAgeError as e:
print(f"오류: {e.age}는 {e.message}")
이 예제에서는 음수의 나이를 입력하면 InvalidAgeError를 발생시키고, 예외를 처리하여 사용자에게 유효하지 않은 나이임을 알립니다.
# 5. 예외 처리 모범사례
예외 처리를 잘못하면 코드의 가독성이 떨어지고, 유지 보수가 어려워질 수 있습니다.
다음은 예외 처리 시 고려해야 할 베스트 프랙티스( 모범사례 ) 입니다.
- 예외 남용 방지
- 예외는 프로그램의 흐름을 제어하는 수단으로 남용하지 않아야 합니다. 예외는 진짜 예외 상황에서만 사용하고, 일반적인 조건문으로 처리할 수 있는 상황에서는 예외를 사용하지 않는 것이 좋습니다.
- 적절한 에러 메시지 작성하기
- 에러 메시지는 명확하고 구체적이어야 합니다. 사용자가 문제를 이해하고 해결할 수 있도록 도움이 되는 정보를 제공하는 것이 중요합니다.
- 로깅(logging)과 예외 처리의 관계
- 로깅을 활용하여 예외 발생 시 기록을 남기면, 문제를 파악하고 추적하는 데 도움이 됩니다. 특히, 실무 환경에서는 로깅을 통해 예외 발생 원인을 신속히 파악할 수 있습니다.
실무 예제: 로깅을 활용한 예외 처리
🚩 로깅을 활용한 예외 처리 🚩
import logging
logging.basicConfig(filename='app.log', level=logging.ERROR)
try:
x = 1 / 0
except ZeroDivisionError as e:
logging.error("0으로 나눌 수 없습니다.", exc_info=True)
print("오류가 발생했습니다. 로그를 확인하세요.")
이 코드는 예외가 발생할 때 로그 파일에 오류 정보를 기록하고, 사용자에게 로그를 확인하도록 안내합니다.
# 5. 마무리
이번 포스팅에서는 파이썬에서 예외를 처리하는 다양한 방법과 실무에서 유용한 예제들을 살펴보았습니다. 예외 처리는 코드의 안정성과 신뢰성을 높이는 중요한 기술이며, 적절히 활용하면 예기치 않은 상황에서도 프로그램이 중단되지 않고 정상적으로 동작할 수 있습니다. 이 글을 통해 배운 예외 처리 기법을 실무에 적용해 보세요.