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

Python 개선 제안 한국어 번역

PEP 409 – 예외 컨텍스트 억제

Author:
Ethan Furman <ethan at stoneleaf.us>
Status:
Final
Type:
Standards Track
Created:
26-Jan-2012
Python-Version:
3.3
Post-History:
30-Aug-2002, 01-Feb-2012, 03-Feb-2012
Superseded-By:
415
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

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

초록

아직 해결되지 않은 PEP 3134의 문제 중 하나는 컨텍스트를 억제하는 것입니다. 현재 이를 수행할 방법이 없습니다. 이 PEP는 그 방법을 제안합니다.

근거

예외를 생성하는 기본적인 방법은 두 가지입니다.

  1. Python이 수행합니다(버그가 있는 코드, 누락된 리소스, 루프 종료 등으로).
  2. 수동으로 (raise 문을 사용하여)

라이브러리나 단순히 사용자 정의 클래스를 작성할 때 예외를 발생시켜야 할 수 있으며, 한 예외를 다른 예외로 변경하는 것이 유용하거나 심지어 필요할 수도 있습니다. 제 dbf 모듈의 예를 들면 다음과 같습니다.:

try:
    value = int(value)
except Exception:
    raise DbfError(...)

원래 예외가 무엇이었는지(ValueError, TypeError, 또는 다른 예외인지는) 중요하지 않습니다. 이 시점부터의 예외는 DbfError이며, 원래 예외는 아무런 가치가 없습니다. 그러나 현재 이 예외를 출력하면 두 예외가 모두 표시됩니다.

대안

몇 가지 가능성이 제시되었습니다.

  • raise as NewException()

    as키워드를 재사용합니다. 실제로는 원래 예외를 다시 발생시키는 것이 아니므로 혼동될 수 있습니다.

  • raise NewException() from None

    원래 예외를 명시적으로 선언하는 기존 구문을 따릅니다.

  • exc = NewException(); exc.__context__ = None; raise exc

    앞선 방법을 매우 장황하게 표현한 방식입니다.

  • raise NewException.no_context(...)

    컨텍스트 억제를 클래스 메서드로 만듭니다.

위의 모든 선택 사항은 코어를 변경해야 합니다.

제안

두 번째 선택 사항을 사용하는 것을 제안합니다.:

raise NewException from None

원인을 명시적으로 설정하는 기존 패턴을 사용한다는 장점이 있습니다.:

raise KeyError() from NameError()

하지만 원인이 None이므로 기본 예외 출력 루틴에서는 이전 컨텍스트가 표시되지 않습니다.

구현 논의

참고: 이 PEP가 승인된 후 더 깔끔한 구현 메커니즘이 제안되었고 PEP 415에서 승인되었습니다. 실제로 Python 3.3에서 사용된 구현에 대한 자세한 내용은 해당 PEP를 참조하십시오.

현재 __context____cause__모두의 기본값은 None입니다. raise ... from None을 지원하려면(__cause__None으로 설정하게 됨) __cause__에 다른 기본값이 필요합니다. 이를 언어 수준에서 구현하는 방법에 관해 몇 가지 아이디어가 제시되었습니다.

  • 이전 예외 정보를 덮어씁니다(__cause__None으로 둠으로써 문제를 우회합니다).

    poor error messages 때문에 디버깅을 심각하게 방해할 수 있으므로 거부되었습니다.

  • __cause__에 불리언 값 중 하나를 사용합니다. False가 기본값이 되고, from ...이 명시적으로 연결된 예외 또는 None과 함께 사용되면 해당 값으로 대체됩니다.

    이는 __cause__에 서로 다른 두 객체 타입을 사용하도록 조장하며, 그중 하나인 불리언 타입은 가능한 값의 전체 범위를 사용할 수 없으므로(True는 절대 사용되지 않음) 거부되었습니다.

  • 특수 예외 클래스인 __NoException__을 만듭니다.

    혼란을 일으킬 수 있고, 사용자가 실수로 발생시킬 수도 있으며, None, True, False와 같이 진정으로 고유한 값도 아니므로 거부되었습니다.

  • 기본값으로 Ellipsis를 사용합니다(... 싱글턴).

    채택되었습니다.

    영어에서는 단어가 생략될 때 줄임표를 자리 표시자로 흔히 사용합니다. 여기서는 이것이 __cause__가 생략되었다는 신호로 작동하므로, 자세한 내용은 __context__에서 확인하면 됩니다.

    Ellipsis는 예외가 아니므로 발생시킬 수 없습니다.

    Ellipsis는 하나뿐이므로 사용되지 않는 값이 없습니다.

    오류 정보가 버려지지 않으므로 기본 코드가 추적하지 않더라도 사용자 정의 코드로 전체 예외 체인을 추적할 수 있습니다.

언어 세부 사항

raise Exception from None을 지원하기 위해 __context__는 현재 상태로 유지되지만, __cause__는 처음에 Ellipsis로 시작하고 raise Exception from None방식이 사용되면 None으로 변경됩니다.

형식 __context__ __cause__
발생 None Ellipsis
재발생 이전 예외 Ellipsis
None에서 재발생 | ChainedException에서 재발생 이전 예외 None | 명시적으로 연결된 예외

그러면 기본 예외 출력 루틴은 다음과 같이 동작합니다.

  • __cause__Ellipsis이면 __context__(있는 경우)가 출력됩니다.
  • __cause__None이면 __context__는 출력되지 않습니다.
  • __cause__가 그 외의 값이면 __cause__가 출력됩니다.

두 경우 모두 예외 체인 추적이 중단됩니다.

__cause__의 기본값이 이제 Ellipsis이고, raise Exception from Cause는 단순히 다음에 대한 구문 설탕이기 때문에:

_exc = NewException()
_exc.__cause__ = Cause()
raise _exc

EllipsisNone과 마찬가지로 이제 원인으로 허용됩니다:

raise Exception from Ellipsis

패치

이를 구현한 CPython용 패치가 Issue 6210에 첨부되어 있습니다.

참고 자료

thread on python-dev에서 논의와 개선 사항을 확인할 수 있습니다.