[Python] Skill of coding - try/except/else/finaly

try/except/else/finaly 에서 각 블록의 장점을 이용

예외 처리 과정에서 동작을 넣을 수 있는 네 번의 구분되는 시점이 있어요.
try, except, else, finaly 블록 기능으로 각 시점을 처리 할 수 있어요.
각 블록은 복함문에서 독자적인 목적이 있으며, 이블록들을 다양하게 조합하면 유용해요.

finally 블록

예외를 전달하고 싶지만, 예외가 발생해도 정리 코드를 실행하고 싶을 때 try/finally를 사용하세요.

일반적인 예, 파일 핸들러를 제대로 종료하는 작업!

handle = open('random_data.txt', 'w', encoding='utf-8')
handle.write('success\nand\nnew\nlines')
handle.close()
handle = open('random_data.txt')  # May raise IOError
try:
    data = handle.read()  # May raise UnicodeDecodeError
finally:
    handle.close()        # Always runs after try:

read 메서드에서 발생한 예외는 항상 코드까지 전달되며, handle의 close메서드 또한 finally 블럭에서 실행되는 것이 보장되요. 파일이 없을 때 일어나는 IOError처럼 파일을 열 때 일어나는 예외는 finally 블럭에서 처리하지 않아야 하므로 try 블럭 앞에서 open을 호출해야해요.

else블록

코드에서 어떤 예외를 처리하고 어떤 예외를 전달할지를 명확하게 하려면 try/except/else를 사용해야 합니다. try 블록이 예외를 일으키지 않으면 else블록이 실행되요. else블록이 사용되면 try 블록의 코드를 최소로 줄이고 가독성을 높일 수 있어요. 예를 들어 문자열에서 JSON 딕셔너리 데이터를 로드하여 그 안에 든 키의 값을 반환한다고 할게요.

import json

def load_json_key(data, key):
    try:
        result_dict = json.loads(data)  # May raise ValueError
    except ValueError as e:
        raise KeyError from e
    else:
        return result_dict[key]         # May raise KeyError

데이터가 올바른 JSON이 아니라면 json.load로 디코드할 때 ValueError가 일어나요. 이 예외는 except 블록에서 발견되어 처리되요. 디코딩이 성공하며녀 else 블록에서 키를 찾아요. 키를 찾을 떄 어떤 예외가 일어나면 그 예외는 try블록 밖에 있으므로 호출 코드까지 전달되요. else 절은 try/except 다음에 나오는 처리를 시각적으로 except블록과 구분해줘요. 그래서 예외 전달 행위를 명확하게 합니다

함께 사용하기

복합문 하나로 모든 것을 처리하고 싶다면 try/except/else/finally를 사용하면 되요.
예를 들어 파일에서 수행할 작업 설명을 읽고 처리한 후 즉석에서 파일을 업데이트 한다고 할게요.

try 블록은 파일을 읽고 처리하는 데 사용되요.
except 블록은 try 블록에서 일어난 예외를 처리하는데 사용되요.
else블록은 파일을 즉석에서 업데이트하고 이와 관련한 예외가 전달되게 하는데 사용되요.
finally 블럭은 파일 핸들을 정리하는데 사용되요.

import json
UNDEFINED = object()

def divide_json(path):
    handle = open(path, 'r+')   # May raise IOError
    try:
        data = handle.read()    # May raise UnicodeDecodeError
        op = json.loads(data)   # May raise ValueError
        value = (
            op['numerator'] /
            op['denominator'])  # May raise ZeroDivisionError
    except ZeroDivisionError as e:
        return UNDEFINED
    else:
        op['result'] = value
        result = json.dumps(op)
        handle.seek(0)
        handle.write(result)    # May raise IOError
        return value
    finally:
        handle.close()          # Always runs

# Everything works
temp_path = 'random_data.json'
handle = open(temp_path, 'w')
handle.write('{"numerator": 1, "denominator": 10}')
handle.close()
assert divide_json(temp_path) == 0.1

# Divide by Zero error
handle = open(temp_path, 'w')
handle.write('{"numerator": 1, "denominator": 0}')
handle.close()
assert divide_json(temp_path) is UNDEFINED

# JSON decode error
handle = open(temp_path, 'w')
handle.write('{"numerator": 1 bad data')
handle.close()
try:
    divide_json(temp_path)
    assert False
except ValueError:
    pass  # Expected

이 레이아웃은 모든 블럭이 직관적인 방식으로 엮여서 동작하므로 특히 유용해요. 예를들어 결과 데이터를 재작성하는 동안에 else블록에서 예외가 일어나도 finally 블록은 여전히 실행되어 파일 핸들을 닫아요.

핵심 정리

try/finally 복함분을 이용하면 try 블록에서 예외 발생 여부와 상관없이 정리 코드를 실행 할 수 있어요.
else 블록은 try 블록에 있는 코드의 양을 최소로 줄이는데 도움을 주며 try/except 블록과 성공한 경우에 실행할 코드를 시각적으로 구분해줘요.
else 블럭은 try 코드가 성공적으로 실행된 후 finally 블록에서 공통정리 코드를 실행하기 전에 추가 작업을 하는데 사용할 수 있어요.

좋은 웹페이지 즐겨찾기