에러와 예외
에러와 예외
파이썬의 에러와 예외
1. 문법 에러 (SyntaxError)
- 파싱 에러라고도 불림
- 파이썬 코드의 구문이 올바르지 않을 때 발생
while True print('Hello world')
# SyntaxError: invalid syntax
SyntaxError: invalid syntax`
특징:
- 에러가 발생한 위치를 화살표(^)로 표시
- 파일 이름과 줄 번호 제공
2. 예외 (Exceptions)
- 문법적으로 올바르지만 실행 중에 발생하는 에러
- 항상 치명적이지는 않음 (처리 가능)
주요 예외 유형:
- ZeroDivisionError
10 * (1/0)
# ZeroDivisionError: division by zero
- NameError
4 + spam*3
# NameError: name 'spam' is not defined
- TypeError
'2' + 2
# TypeError: can only concatenate str (not "int") to str
예외 메시지의 구조
- 스택 트레이스: 예외가 발생한 위치와 문맥 제공
- 예외 유형: 발생한 예외의 이름 (예: ZeroDivisionError)
- 상세 설명: 예외의 원인에 대한 구체적인 설명
주요 포인트
- 문법 에러는 코드 실행 전에 발견됨
- 예외는 코드 실행 중에 발생
- 예외는 처리 가능하며, 프로그램의 흐름을 제어하는 데 사용될 수 있음
- 표준 예외 이름은 내장 식별자
이해:
- 문법 에러와 예외를 구분하는 것이 중요
- 예외 메시지를 해석하고 이해하는 능력이 디버깅에 중요
- 예외 처리를 통해 더 견고한 프로그램 작성 가능
파이썬의 예외 처리
1. try-except 구문
기본 구조:
try:
# 실행할 코드
except ExceptionType:
# 예외 처리 코드
작동 방식:
- try 절 실행
- 예외 발생 시, 해당 except 절로 이동
- 예외 없으면 except 절 건너뜀
2. 다중 예외 처리
여러 예외 동시 처리:
try:
# 코드
except (TypeError, ValueError):
# 처리
예외 계층 구조 활용:
- 상위 클래스 예외가 하위 클래스 예외도 포착
3. 예외 정보 활용
예외 인스턴스 접근:
try:
raise Exception('메시지')
except Exception as e:
print(type(e)) # 예외 타입
print(e.args) # 예외 인자
print(e) # 문자열 표현
4. 주요 예외 클래스
- BaseException: 모든 예외의 기본 클래스
- Exception: 대부분의 예외 처리에 사용
- SystemExit, KeyboardInterrupt: 프로그램 종료 관련
5. else와 finally 절
else: 예외가 발생하지 않았을 때 실행
finally: 예외 발생 여부와 관계없이 항상 실행
try:
# 코드
except ExceptionType:
# 예외 처리
else:
# 예외 없을 때 실행
finally:
# 항상 실행
6. 예외 처리 모범 사례
- 구체적인 예외 처리
- 예상치 못한 예외는 상위로 전파
- 로깅 활용
- 필요시 예외 재발생
주요 포인트
- 예외 처리로 프로그램 안정성 향상
- 적절한 예외 타입 선택 중요
- else 절로 예외 없는 경우 명확히 구분
- 함수 호출 시 발생하는 예외도 처리 가능
파이썬의 예외 일으키기 (Raising Exceptions)
1. raise 문 기본 사용법
raise ExceptionType('Error message')
2. 예외 클래스와 인스턴스
- 예외 인스턴스 사용:
raise ValueError('Invalid value')
- 예외 클래스 사용 (인자 없이):
raise ValueError # 'raise ValueError()' 와 동일
3. 예외 다시 일으키기
예외를 잡은 후 다시 발생시키기:
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
raise
를 인자 없이 사용하면 현재 처리 중인 예외를 다시 발생시킴
4. 주요 포인트
raise
는 의도적으로 예외를 발생시킬 때 사용- 예외 클래스나 예외 인스턴스를 인자로 받음
- 예외 클래스만 지정하면 기본 생성자 호출
- 예외를 잡은 후 다시 발생시켜 상위 레벨에서 처리 가능
5. 사용 예시 및 팁
- 사용자 정의 예외 발생:
class CustomError(Exception):
pass
raise CustomError("This is a custom error")
- 조건부 예외 발생:
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
- 예외 체이닝:
try:
# some code
except SomeException as e:
raise RuntimeError("A runtime error occurred") from e
- 예외 무시하기 (권장되지 않음):
try:
# some code
except SomeException:
pass # 예외를 무시
파이썬의 예외 연쇄 (Exception Chaining)
예외 연쇄는 한 예외가 다른 예외의 직접적인 원인임을 나타내는 메커니즘입니다. 이를 통해 예외의 원인을 더 명확히 추적할 수 있습니다.
1. 자동 예외 연쇄
예외 처리 중 새로운 예외가 발생할 때 자동으로 연쇄됩니다.
try:
open("database.sqlite")
except OSError:
raise RuntimeError("unable to handle error")
출력:
FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite'
During handling of the above exception, another exception occurred:
RuntimeError: unable to handle error
2. 명시적 예외 연쇄
raise ... from ...
구문을 사용하여 명시적으로 예외를 연쇄할 수 있습니다.
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from exc
출력:
ConnectionError
The above exception was the direct cause of the following exception:
RuntimeError: Failed to open database
3. 예외 연쇄 비활성화
from None
을 사용하여 자동 예외 연쇄를 비활성화할 수 있습니다.
try:
open('database.sqlite')
except OSError:
raise RuntimeError from None
출력:
RuntimeError
4. 주요 포인트
- 자동 연쇄: except 블록 내에서 새 예외 발생 시 자동으로 연결됨
- 명시적 연쇄:
raise ... from exc
로 직접 연결 가능 - 연쇄 비활성화:
raise ... from None
으로 연결 제거 가능 - 목적: 예외의 원인을 더 명확히 추적하고 디버깅을 용이하게 함
파이썬의 사용자 정의 예외 (Custom Exceptions)
사용자 정의 예외를 생성하면 프로그램 특정의 오류 상황을 더 명확하게 표현할 수 있습니다.
1. 기본 사용자 정의 예외 생성
class CustomError(Exception):
pass
- 대부분의 사용자 정의 예외는
Exception
클래스를 직접 또는 간접적으로 상속받습니다.
2. 속성을 가진 사용자 정의 예외
class ValueTooSmallError(Exception):
def __init__(self, message, value):
self.message = message
self.value = value
def __str__(self):
return f'{self.message}: {self.value}'
3. 예외 계층 구조 만들기
class DatabaseError(Exception):
pass
class ConnectionError(DatabaseError):
pass
class QueryError(DatabaseError):
pass
4. 주요 포인트
- 명명 규칙: 대부분 "Error"로 끝나는 이름 사용
- 단순성: 일반적으로 간단하게 유지
- 속성: 오류에 대한 추가 정보를 제공하는 속성 포함 가능
- 계층 구조: 관련 예외들을 그룹화하여 계층 구조 생성 가능
파이썬의 뒷정리 동작 (Cleanup Actions)
finally
절은 예외 처리와 관계없이 항상 실행되어야 하는 코드를 정의하는 데 사용됩니다.finally
절을 적절히 활용하면 리소스 관리와 예외 상황에서의 안정성을 크게 향상시킬 수 있습니다.
특히 외부 리소스를 다룰 때 finally
를 사용하여 리소스 누수를 방지하는 것이 중요합니다
1. finally 절의 기본 사용
try:
# 실행할 코드
except SomeException:
# 예외 처리
finally:
# 항상 실행되는 코드
2. finally 절의 특징
- 예외 발생 여부와 관계없이 항상 실행됨
- try, except, else 절에서 예외가 발생해도 실행됨
- 함수의 return, break, continue 문 실행 전에 실행됨
3. finally 절의 주요 용도
- 리소스 해제 (파일 닫기, 네트워크 연결 종료 등)
- 임시 상태 정리
- 로깅 또는 정리 작업 수행
4. 주의사항
- finally 절에서 return 문 사용 시, 이 값이 최종 반환값이 됨
- finally 절에서 예외가 발생하면, 이전 예외를 덮어씀
5. 사용 예시 및 팁
- 파일 처리:
try:
f = open('file.txt', 'r')
# 파일 작업
except IOError:
print("파일을 열 수 없습니다.")
finally:
f.close() # 파일을 항상 닫음
- 데이터베이스 연결:
import sqlite3
conn = sqlite3.connect('example.db')
try:
# 데이터베이스 작업
except sqlite3.Error as e:
print(f"데이터베이스 오류: {e}")
finally:
conn.close() # 연결을 항상 닫음
- 임시 상태 정리:
temp_file = 'temp.txt'
try:
with open(temp_file, 'w') as f:
# 임시 파일 작업
finally:
import os
os.remove(temp_file) # 임시 파일 항상 삭제
파이썬의 미리 정의된 뒷정리 동작과 with 문
파이썬에서는 특정 객체들이 자동으로 리소스를 해제하는 뒷정리 동작을 정의합니다. with
문은 이러한 객체들을 안전하게 사용할 수 있게 해주는 편리한 구문입니다.
1. with 문의 기본 사용
with context_manager as variable:
# 작업 수행
context_manager
:__enter__
와__exit__
메서드를 구현한 객체- 블록이 종료되면 자동으로
__exit__
메서드 호출 (리소스 해제)
2. 파일 처리 예시
기존 방식:
for line in open("myfile.txt"):
print(line, end="")
문제점: 파일이 명시적으로 닫히지 않음
with 문 사용:
with open("myfile.txt") as f:
for line in f:
print(line, end="")
장점: 블록 종료 시 자동으로 파일 닫힘
3. with 문의 장점
- 리소스 자동 해제
- 예외 발생 시에도 안전하게 리소스 해제
- 코드 간결성 및 가독성 향상
4. 주요 사용 사례
- 파일 처리:
with open('file.txt', 'w') as f:
f.write('Hello, World!')
- 데이터베이스 연결:
import sqlite3
with sqlite3.connect('example.db') as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
- 네트워크 연결:
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(('example.com', 80))
s.sendall(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
data = s.recv(1024)
- 잠금(Lock) 관리:
import threading
lock = threading.Lock()
with lock:
# 임계 영역 코드
5. 사용자 정의 컨텍스트 매니저
class MyContextManager:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting the context")
if exc_type is not None:
print(f"An exception occurred: {exc_type}, {exc_value}")
return False # 예외를 다시 발생시킴
with MyContextManager() as mgr:
print("Inside the context")
주요 포인트
with
문은 자동 리소스 관리를 제공- 예외 발생 시에도 안전하게 리소스 해제
- 코드를 더 간결하고 읽기 쉽게 만듦
- 파일, 데이터베이스 연결, 네트워크 소켓 등에 널리 사용
- 사용자 정의 컨텍스트 매니저를 만들어 사용 가능
파이썬의 다중 예외 발생 및 처리
Python 3.11부터 도입된 ExceptionGroup
과 except*
구문을 사용하여 여러 개의 관련 없는 예외를 동시에 처리할 수 있습니다.
1. ExceptionGroup
ExceptionGroup
은 여러 예외 인스턴스를 하나의 그룹으로 묶어 발생시킬 수 있게 해줍니다.
def f():
excs = [OSError('error 1'), SystemError('error 2')]
raise ExceptionGroup('there were problems', excs)
try:
f()
except Exception as e:
print(f'caught {type(e)}: {e}')
2. except* 구문
try:
f()
except* OSError as e:
print("There were OSErrors")
except* SystemError as e:
print("There were SystemErrors")
3. 중첩된 ExceptionGroup
ExceptionGroup
안에 다른 ExceptionGroup
을 포함할 수 있습니다.
def f():
raise ExceptionGroup(
"group1",
[
OSError(1),
SystemError(2),
ExceptionGroup(
"group2",
[
OSError(3),
RecursionError(4)
]
)
]
)
4. 주요 포인트
ExceptionGroup
은 여러 예외를 그룹화합니다.except*
는ExceptionGroup
내의 특정 타입 예외만 처리합니다.- 처리되지 않은 예외는 다시 발생됩니다.
ExceptionGroup
에는 예외 인스턴스만 포함될 수 있습니다 (타입이 아님).
5. 실제 사용 예시
excs = []
for test in tests:
try:
test.run()
except Exception as e:
excs.append(e)
if excs:
raise ExceptionGroup("Test Failures", excs)
이 기능은 동시성 프레임워크나 여러 작업을 병렬로 실행하는 경우, 또는 여러 오류를 수집하고 싶을 때 유용합니다.
복잡한 예외 상황을 더 세밀하게 제어하고 처리할 수 있게 해주며, 특히 대규모 애플리케이션이나 라이브러리에서 유용하게 사용될 수 있습니다.
파이썬의 예외 정보 강화 (Enriching Exceptions with Notes)
Python 3.11부터 도입된 add_note()
메서드를 사용하여 예외에 추가 정보를 덧붙일 수 있습니다.
이 기능은 예외 처리 과정에서 더 상세한 컨텍스트 정보를 제공하는 데 유용합니다.
1. add_note() 메서드
add_note(note)
메서드는 예외 객체에 문자열 형태의 노트를 추가합니다.
try:
raise TypeError('bad type')
except Exception as e:
e.add_note('Add some information')
e.add_note('Add some more information')
raise
출력:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: bad type
Add some information
Add some more information
2. ExceptionGroup과 함께 사용
add_note()
는 ExceptionGroup
과 함께 사용하여 각 예외에 컨텍스트 정보를 추가할 때 특히 유용합니다.
def f():
raise OSError('operation failed')
excs = []
for i in range(3):
try:
f()
except Exception as e:
e.add_note(f'Happened in Iteration {i+1}')
excs.append(e)
raise ExceptionGroup('We have some problems', excs)
3. 주요 포인트
add_note()
메서드로 예외에 추가 정보를 덧붙일 수 있습니다.- 추가된 노트는 표준 트레이스백 렌더링에 포함됩니다.
- 노트는 추가된 순서대로 표시됩니다.
- 이 기능은 예외의 컨텍스트나 디버깅 정보를 제공하는 데 유용합니다.