5 파이썬의 오류 처리 패턴 (Try-Excrect 이상)

5 파이썬의 오류 처리 패턴 (Try-Excrect 이상)

5 파이썬의 오류 처리 패턴저자의 이미지 | 캔버

오류 처리와 관련하여 우리가 일반적으로 배우는 첫 번째 것은 Try-excrect 블록을 사용하는 방법입니다. 그러나 코드베이스가 더 복잡해지면서 충분합니까? 나는 믿지 않는다. 시도 코스에만 의존하면 반복적이고 혼란스럽고 관리하기 어려운 코드로 이어질 수 있습니다.

이 기사에서는 안내해 드리겠습니다 5 고급의 실용적인 오류 처리 패턴 이로 인해 코드를 더 깨끗하고 신뢰할 수 있으며 디버깅하기가 더 쉬워 질 수 있습니다. 각 패턴에는 실제 예제가 함께 제공되므로 어디에서 왜 의미가 있는지 확인할 수 있습니다. 그래서 시작합시다.

1. 배치 처리를위한 오류 집계

여러 항목을 처리 할 때 (예 : 루프에서) 일부 항목이 실패하더라도 처리를 계속할 수 있습니다. 그런 다음 마지막에 모든 오류를보고 할 수 있습니다. 이 패턴은 호출됩니다 오류 집계첫 번째 실패로 멈추지 않습니다. 이 패턴은 양식 검증, 데이터 가져 오기 시나리오 또는 첫 번째 오류를 중지하지 않고 모든 문제에 대한 포괄적 인 피드백을 제공하려는 상황에 적합합니다.

예: 사용자 레코드 목록 처리. 일부 실패하더라도 계속하십시오.

def process_user_record(record, record_number):
    if not record.get("email"):
        raise ValueError(f"Record #{record_number} failed: Missing email in record {record}")
    
    # Simulate processing
    print(f"Processed user #{record_number}: {record['email']}")

def process_users(records):
    errors = []
    for index, record in enumerate(records, start=1):  
        try:
            process_user_record(record, index)
        except ValueError as e:
            errors.append(str(e))
    return errors

users = [
    {"email": "[email protected]"},
    {"email": ""},
    {"email": "[email protected]"},
    {"email": ""}
]

errors = process_users(users)

if errors:
    print("\nProcessing completed with errors:")
    for error in errors:
        print(f"- {error}")
else:
    print("All records processed successfully")

이 코드는 사용자 레코드 및 프로세스를 개별적으로 처리합니다. 레코드에 이메일이 없으면 ValueError가 제기되어 오류 목록에 잡히고 저장됩니다. 프로세스는 모든 레코드에 대해 계속되며, 이와 같이 전체 배치를 중지하지 않고 끝에 모든 실패가보고됩니다.

Output:
Processed user #1: [email protected]
Processed user #3: [email protected]

Processing completed with errors:
- Record #2 failed: Missing email in record {'email': ''}
- Record #4 failed: Missing email in record {'email': ''}

2. 자원 관리를위한 컨텍스트 관리자 패턴

파일, 데이터베이스 연결 또는 네트워크 소켓과 같은 리소스로 작업 할 때 오류가 발생하더라도 올바르게 열리고 닫아야합니다. 컨텍스트 관리자는 with 문을 사용하여이를 자동으로 처리하여 수동 트러블 핀 블록에 비해 리소스 누출 가능성을 줄입니다. 이 패턴은 특히 I/O 운영 또는 외부 시스템을 처리 할 때 특히 유용합니다.

예: CSV 파일을 읽고 있으며 파일 처리가 실패하더라도 올바르게 닫히고 싶다고 가정 해 봅시다.

import csv

def read_csv_data(file_path):
    try:
        with open(file_path, 'r') as file:
            print(f"Inside 'with': file.closed = {file.closed}")  # Should be False
            reader = csv.reader(file)
            for row in reader:
                if len(row) 

이 코드는 A With Statement (Context Manager)를 사용하여 파일을 안전하게 열고 읽습니다. 어떤 행이든 2 값 미만인 경우 ValueError그러나 파일은 여전히 ​​자동으로 닫힙니다. 그만큼 file.closed 점검은 블록 내부와 후에 파일의 상태를 확인합니다. 이 동작을 관찰하기 위해 위의 코드를 실행합시다.

Output:
Inside 'with': file.closed = False
['Name', 'Age']
['Sarwar', '30']
Error: Invalid row format
In except block: file is closed? True

3. 상황에 맞는 오류에 대한 예외 포장

때로는 하위 수준의 기능에서 예외가 더 넓은 응용 프로그램에서 무엇이 잘못되었는지에 대한 컨텍스트를 충분히 제공하지 않습니다. 예외 포장 (또는 체인)을 사용하면 예외를 포착하고 컨텍스트를 추가하며 원본을 포함하는 새로운 예외를 다시 만들 수 있습니다. 계층화 된 응용 프로그램 (예 : API 또는 서비스)에 특히 유용합니다.

예: 데이터베이스에서 사용자 데이터를 가져오고 데이터베이스 오류가 발생할 때 컨텍스트를 제공하려고한다고 가정하십시오.

class DatabaseAccessError(Exception):
    """Raised when database operations fail."""
    pass

def fetch_user(user_id):
    try:
        # Simulate database query
        raise ConnectionError("Failed to connect to database")
    except ConnectionError as e:
        raise DatabaseAccessError(f"Failed to fetch user {user_id}") from e

try:
    fetch_user(123)
except DatabaseAccessError as e:
    print(f"Error: {e}")
    print(f"Caused by: {e.__cause__}")

그만큼 ConnectionError 잡히고 싸여 있습니다 Databaseaccesserror 사용자 ID에 대한 추가 컨텍스트. From e 구문은 원래 예외를 연결하므로 전체 오류 체인을 디버깅 할 수 있습니다. 출력은 다음과 같습니다.

Output:
Error: Failed to fetch user 123
Caused by: Failed to connect to database

4. 과도 실패에 대한 재 시도 논리

네트워크 타임 아웃 또는 임시 서비스를 이용할 수없는 것과 같은 일부 오류는 일시적이며 레트리에서 해결 될 수 있습니다. 재 시도 패턴을 사용하면 수동 루프로 코드를 어수선하지 않고도 이러한 우아하게 처리 할 수 ​​있습니다. 임시 실패로부터 복구를 자동화합니다.

예: 시뮬레이션 된 네트워크 오류로 인해 때때로 실패하는 플라킹 API 호출을 다시합시다. 아래 코드는 회수간에 고정 된 지연으로 API 호출을 여러 번 시도합니다. 통화가 성공하면 결과를 즉시 반환합니다. 모든 검색이 실패하면 발신자가 처리 할 예외가 발생합니다.

import random
import time

def flaky_api_call():
    # Simulate 50% chance of failure (like timeout or server error)
    if random.random() 
Output:
Attempt 1 failed: Simulated network failure. Retrying in 2 seconds...
API call succeeded: {'status': 'success', 'data': [1, 2, 3]}

보시다시피, 시뮬레이션 된 네트워크 오류로 인해 첫 번째 시도가 실패했습니다 (무작위로 50%가 발생 함). 재 시도 로직은 2 초 동안 기다린 다음 다음 시도에서 API 호출을 성공적으로 완료했습니다.

5. 도메인 별 오류에 대한 사용자 정의 예외 클래스

같은 일반적인 예외에 의존하는 대신 ValueError 또는 runtimeerror응용 프로그램 도메인에서 특정 오류를 나타 내기 위해 사용자 정의 예외 클래스를 만들 수 있습니다. 이로 인해 오류 처리가 더 시맨틱하고 유지하기가 더 쉬워집니다.

예: 다른 유형의 지불 실패에 특정 처리가 필요한 결제 처리 시스템을 가정 해보십시오.

class PaymentError(Exception):
    """Base class for payment-related exceptions."""
    pass

class InsufficientFundsError(PaymentError):
    """Raised when the account has insufficient funds."""
    pass

class InvalidCardError(PaymentError):
    """Raised when the card details are invalid."""
    pass

def process_payment(amount, card_details):
    try:
        if amount > 1000:
            raise InsufficientFundsError("Not enough funds for this transaction")
        if not card_details.get("valid"):
            raise InvalidCardError("Invalid card details provided")
        print("Payment processed successfully")
    except InsufficientFundsError as e:
        print(f"Payment failed: {e}")
        # Notify user to top up account
    except InvalidCardError as e:
        print(f"Payment failed: {e}")
        # Prompt user to re-enter card details
    except Exception as e:
        print(f"Unexpected error: {e}")
        # Log for debugging

process_payment(1500, {"valid": False})

사용자 정의 예외 (InsufficiTedFundError, InvalidCardError)는 기본 지불 오류 클래스에서 상속되므로 일반적인 예외 블록으로 예기치 않은 오류를 포착하면서 특정 결제 문제를 다르게 처리 할 수 ​​있습니다. 예를 들어, call process_payment (1500, { “valid”: false})금액 (1500)이 1000을 초과하기 때문에 첫 번째 점검이 트리거되므로 불충분 한 FundSerror가 발생합니다. 이 예외는 블록, 인쇄를 제외한 해당 해당에 포착됩니다.

Output:
Payment failed: Not enough funds for this transaction

결론

그게 다야. 이 기사에서는 5 가지 실용적인 오류 처리 패턴을 탐색했습니다.

  1. 오류 집계 : 모든 항목을 처리하고 오류를 수집하여 함께보고하십시오
  2. 컨텍스트 관리자 : 블록과 함께 파일과 같은 리소스를 안전하게 관리합니다
  3. 예외 포장 : 예외를 잡고 다시 만들어 컨텍스트를 추가하십시오
  4. 재 시도 로직 : 네트워크 고장과 같은 과도 오류를 자동으로 재 시도합니다
  5. 사용자 정의 예외 : 명확한 처리를 위해 특정 오류 클래스를 만듭니다

다음 프로젝트에서 이러한 패턴을 시도하십시오. 약간의 연습을 통해 코드를 유지하기가 더 쉽고 오류 처리가 훨씬 더 효과적입니다.

Kanwal Mehreen Kanwal은 머신 러닝 엔지니어이자 데이터 과학에 대한 열정과 AI의 의학 교차점을 가진 기술 작가입니다. 그녀는 eBook “Chatgpt의 생산성을 극대화하는 것”을 공동 저술했습니다. APAC의 Google Generation Scholar 2022로서 그녀는 다양성과 학업 우수성을 챔피언시킵니다. 그녀는 또한 Tech Scholar, Mitacs Globalink Research Scholar 및 Harvard Wecode Scholar의 Teradata 다양성으로 인정 받고 있습니다. Kanwal은 STEM 분야의 여성에게 힘을 실어주기 위해 펨코드를 설립 한 변화에 대한 열렬한 옹호자입니다.

출처 참조

Post Comment

당신은 놓쳤을 수도 있습니다