현대 Python에서 사용자 정의 예외를 선언하는 올바른 방법은 무엇입니까?



Answers

현대 Python 예외를 사용하면 .message 를 남용하거나 .__str__() 또는 .__repr__() 또는 그 중 하나를 무시할 필요가 없습니다. 예외가 발생했을 때 원하는 모든 정보 메시지가 있으면 다음과 같이하십시오.

class MyException(Exception):
    pass

raise MyException("My hovercraft is full of eels")

MyException: My hovercraft is full of eels 끝나는 추적을 제공합니다 MyException: My hovercraft is full of eels 합니다.

더 많은 유연성을 원하면 사전을 인수로 전달할 수 있습니다.

raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})

그러나 except 블록의 세부 정보를 얻는 것은 좀 더 복잡합니다. 그것들은 목록 인 args 속성에 저장됩니다. 다음과 같이해야합니다.

try:
    raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
    details = e.args[0]
    print(details["animal"])

예외에 여러 항목을 전달할 수도 있지만 나중에 사용되지 않을 예정입니다. 하나 이상의 정보가 필요한 경우 Exception 완전히 서브 클래스 화하는 것을 고려해야합니다.

Question

현대 파이썬에서 커스텀 예외 클래스를 선언하는 적절한 방법은 무엇입니까? 내 기본 목표는 다른 표준 클래스를 따르는 것이므로 예외에 포함 된 추가 문자열은 예외를 포착 한 도구로 인쇄됩니다.

"현대 파이썬"이란 파이썬 2.5에서 실행될 것이지만 파이썬 2.6과 파이썬 3에서는 * 올바른 방식 일 것입니다. 그리고 "custom"은 오류의 원인에 대한 추가 데이터를 포함 할 수있는 Exception 객체를 의미합니다. 문자열, 예외와 관련된 임의의 다른 임의의 객체 일 수 있습니다.

Python 2.6.2에서 다음과 같은 deprecation 경고로 인해 문제가 발생했습니다.

>>> class MyError(Exception):
...     def __init__(self, message):
...         self.message = message
... 
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

BaseExceptionmessage 라는 속성에 특별한 의미를 갖는 것은 BaseException 것처럼 보입니다. 나는 PEP-352 에서 속성이 2.5에서 특별한 의미를 가지고 있다는 것을 모았습니다. 그래서 그들은 그 이름을 (그리고 저 혼자서) 금지되었습니다. 응.

나는 또한 Exception 가 일부 마법 매개 변수 args 가지고 있다는 것을 모호하게 알고있다. 그러나 나는 그것을 사용하는 방법을 결코 알지 못했다. 앞으로 나아갈 일이 올바른 방법이라고 확신하지도 않습니다. 필자가 온라인에서 발견 한 많은 토론에서 Python 3에서 args를 제거하려고 시도했다고 제안했습니다.

업데이트 : 두 가지 답변으로 __init____str__ / __unicode__ / __repr__ 재정의하는 것이 좋습니다. 그건 타이핑이 많은 것처럼 보입니다. 필요합니까?




하나 이상의 속성이 사용되는 경우 예외가 어떻게 작동 하는지를보십시오 (역 추적은 생략됩니다) :

>>> raise Exception('bad thing happened')
Exception: bad thing happened

>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')

그래서 당신은 일종의 " 예외 템플릿 "을 가지고 있고, 예외적 인 방식으로 호환되는 방식으로 작업 할 수 있습니다 :

>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened

>>> raise nastyerr()
NastyError: bad thing happened

>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')

이 서브 클래스로 쉽게 할 수있다.

class ExceptionTemplate(Exception):
    def __call__(self, *args):
        return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass

그 기본 튜플과 같은 표현이 마음에 들지 않는다면 ExceptionTemplate 클래스에 __str__ 메소드를 추가하면됩니다 :

    # ...
    def __str__(self):
        return ': '.join(self.args)

너는 가질거야.

>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken



아니요, "메시지"는 금지되어 있지 않습니다. 그냥 비난 받았어. 응용 프로그램은 메시지를 사용하여 정상적으로 작동합니다. 그러나 물론 비추천 오류를 없앨 수 있습니다.

응용 프로그램에 대한 사용자 정의 Exception 클래스를 만들면 Exception에서 서브 클래 싱하지 않고 ValueError 또는 이와 유사한 객체에서 하위 클래스로 분류 할 수 있습니다. 그런 다음 변수 사용에 적응해야합니다.

그리고 응용 프로그램에 많은 예외가있는 경우 모듈의 사용자가 할 수 있도록 모든 모듈에 공통적 인 사용자 정의 기본 클래스를 사용하는 것이 좋습니다.

try:
    ...
except NelsonsExceptions:
    ...

그리고이 경우 __init__ and __str__ 필요하므로 모든 예외에 대해 반복하지 않아도됩니다. 그러나 메시지 변수를 메시지가 아닌 다른 것으로 단순히 호출하는 것은 그 트릭을 수행합니다.

어떤 경우 든 Exception 자체가하는 것과는 다른 것을 할 경우 __init__ or __str__ 만 필요합니다. 그리고 비추천하면 두 가지 모두 필요합니다. 그렇지 않으면 오류가 발생합니다. 클래스별로 필요한 추가 코드가 많이 없습니다. ;)




Links