Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 760 – 맨 except 절 폐지

Author:
Pablo Galindo Salgado <pablogsal at python.org>, Brett Cannon <brett at python.org>
Status:
Withdrawn
Type:
Standards Track
Created:
02-Oct-2024
Python-Version:
3.14
Post-History:
09-Oct-2024

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 Python의 예외 처리 문법에서 단독 except: 절을 허용하지 않을 것을 제안합니다. 현재 Python은 단독 except: 절로 모든 예외를 잡을 수 있도록 허용하는데, 이는 지나치게 광범위한 예외 처리로 이어져 중요한 오류를 가릴 수 있습니다. 이 PEP는 모든 except 절에 예외 타입을 명시하도록 요구하여 더 정확하고 의도가 분명한 오류 처리를 장려할 것을 제안합니다.

동기

현재 문법은 단독 except: 절로 모든 예외를 잡을 수 있도록 허용합니다:

try:
    risky_operation()
except:
    handle_any_error()

이 문법은 “모든 것을 잡는” 핸들러로는 편리할 수 있지만, 종종 좋지 않은 코딩 습관으로 이어집니다:

  1. 전파되어야 할 중요한 오류를 가릴 수 있습니다.
  2. 예상하지 못한 예외를 잡아 숨길 수 있으므로 디버깅이 더 어려워집니다.
  3. 이는 암시적인 것보다 명시적인 것이 낫다는 Python의 원칙에 어긋납니다.

여러 린터 [1] [2] [3]와 스타일 가이드(PEP 8 포함) [4] [5] [6] [7]는 맨 except 절을 권장하지 않습니다.

예외 타입을 명시하도록 요구하면 더 신중하고 정확한 오류 처리를 장려할 수 있습니다:

try:
    risky_operation()
except Exception as e:
    handle_expected_error(e)

이 문제를 다른 관점에서 보면, 맨 except 핸들러는 종료 예외를 어떻게 처리하려는 것인지가 모호합니다. 의도는 다음 둘 중 하나였을 수 있기 때문입니다:

  • 종료 예외가 아닌 예외만 잡습니다(except Exception:). 이것이 의도였다면 맨 except:는 그런 뜻이 아니므로, 이를 사용하는 것은 명백한 버그입니다.
  • 종료 예외를 포함한 모든 예외를 잡습니다(except BaseException:). 이 경우 맨 except:를 사용하는 것이 적어도 틀리지는 않지만, 읽는 사람은 첫 번째 경우에 해당하지 않는지 확인해야 합니다.

두 가지 의도 모두 모호하지 않게 표기할 방법이 이미 있으므로 모호한 형식은 불필요합니다. 이것이 이 형식을 허용하지 않자고 제안하는 이유입니다.

근거

맨 except 절을 허용하지 않기로 한 결정은 다음 사항을 고려한 것입니다:

  1. 구체적인 예외 타입을 요구하면 프로그래머의 의도가 분명해지고, 어떤 예외가 발생할 수 있는지 생각하게 됩니다.
  2. 특정 예외만 잡으면 예상하지 못한 오류를 찾아내고 디버깅하기가 더 쉬워집니다.
  3. 지나치게 넓은 예외 처리를 막으면 치명적인 오류가 조용히 무시될 위험이 줄어듭니다.
  4. 이미 많은 스타일 가이드와 린터가 맨 except 절을 사용하지 말라고 권장합니다.

명세

except 절의 문법은 예외 타입을 요구하도록 수정됩니다. 문법은 except 절에 빈 표현식을 넣을 수 없도록 갱신됩니다.

이 변경으로 단독 except: 문법은 허용되지 않습니다. 모든 except 절은 적어도 하나의 예외 타입을 지정해야 합니다:

try:
    ...
except ValueError:
    ...
except (TypeError, RuntimeError):
    ...
except Exception:
    ...  # Still allowed, but catches all exceptions explicitly

예외 처리의 의미는 바뀌지 않습니다. 다만 BaseException이나 그와 비슷하게 넓은 예외 타입을 명시하지 않고는 모든 예외를 잡을 수 없게 됩니다.

하위 호환성

이 변경은 하위 호환성을 유지하지 않습니다. 맨 except: 절을 사용하는 기존 코드는 수정해야 합니다. 전환을 쉽게 하기 위해 다음 조치를 마련합니다.

  1. Python 3.14에서는 단독 except 절에 대해 폐지 경고가 발생합니다.
  2. Python 3.17에서는 이 문법이 완전히 금지됩니다.
  3. 이전 버전의 Python에서도 맨 except 핸들러를 무효화할 수 있도록 from __future__ import strict_excepts가 제공됩니다.

맨 except:를 except BaseException:으로 바꾸도록 코드를 자동으로 수정하는 도구가 제공됩니다.

보안 영향

이 변경은 보안에 아무런 영향을 미치지 않습니다.

교육 방법

Python을 처음 접하는 사용자에게는 처음부터 명시적인 예외 타입을 사용하여 예외 처리를 가르쳐야 합니다.

try:
    result = risky_operation()
except ValueError:
    handle_value_error()
except TypeError:
    handle_type_error()
except Exception as e:
    handle_unexpected_error(e)

숙련된 사용자에게는 이 변경을 이제 언어 차원에서 강제되는 모범 사례로 소개할 수 있습니다. 다음 사항을 강조해야 합니다.

  1. 가능하면 항상 구체적인 예외를 잡으십시오.
  2. except Exception:은 정말로 예상치 못한 오류에 대한 최후의 수단으로만 사용하십시오.
  3. 신중하게 고려하지 않고 예외를 묵살하는 일은 절대 하지 마십시오.

문서는 일반적인 예외 계층 구조와 잡아야 할 적절한 예외 타입을 선택하는 방법을 안내해야 합니다.

기각된 아이디어

  • 맨 except: 핸들러를 사용하는 것이 올바른 경우도 실제로 존재합니다. Mailman [8]에서 제기된 예시 중 하나는 어떤 예외가 발생하든 트랜잭션을 처리해야 하는 경우입니다.
    @contextmanager
    def transaction():
        """Context manager for ensuring the transaction is complete."""
        try:
            yield
        except:
            config.db.abort()
            raise
        else:
            config.db.commit()
    

    이 코드는 어떤 예외가 발생하든 열려 있는 트랜잭션은 모두 중단되고, 성공한 경우에는 트랜잭션이 커밋되도록 보장합니다.

    이와 같이 맨 except: 핸들러가 올바른 경우가 있기는 하지만, “동기” 절에서 설명한 이유로 실제로는 명시적으로 except BaseException:을 사용하는 편이 더 낫다고 생각합니다.