파이썬 : 어떤 유형의 예외가 발생했는지 어떻게 알 수 있습니까?


230

메인 프로그램에서 호출 한 함수가 있습니다 :

try:
    someFunction()
except:
    print "exception happened!"

그러나 함수 실행 중에 예외가 발생하므로 해당 except부분으로 이동합니다 .

someFunction()예외가 발생한 원인을 정확히 어떻게 알 수 있습니까?


9
지금까지 지금까지 맨손으로 절대 사용하지 마십시오 except:(베어없이 raise)를 제외하고 어쩌면 바람직하게는 다음 프로그램에 한 번합니다.
Mike Graham

여러 except절 을 사용하는 경우 예외 유형을 확인할 필요가 없습니다. 일반적으로 특정 예외 유형에 따라 작동합니다.
Rik Poggi

3
예외 유형에 관심이 있다면 논리적으로 발생할 수있는 예외 유형을 이미 고려했기 때문입니다.
Karl Knechtel

3
내부 except블록 예외는 sys.exc_info()함수를 통해 사용할 수 있습니다. – 이 함수는 현재 처리중인 예외에 대한 정보를 제공하는 세 가지 값의 튜플을 반환합니다.
Piotr Dobrogost

답변:


384

다른 답변은 일반적인 예외를 잡아서는 안된다고 지적하지만 아무도 규칙을 어길 수있는 시점을 이해하는 데 필수적인 이유를 말하고 싶지 않습니다. 여기 에 설명이 있습니다. 기본적으로 숨기지 않습니다.

따라서 이러한 작업을 수행하지 않는 한 일반적인 예외를 잡는 것이 좋습니다. 예를 들어 다음과 같은 다른 방법으로 예외에 대한 정보를 사용자에게 제공 할 수 있습니다.

  • GUI에서 대화 상자로 예외 표시
  • 멀티 스레딩 또는 멀티 프로세싱 응용 프로그램에서 작업자 스레드 또는 프로세스에서 제어 스레드 또는 프로세스로 예외 전송

그렇다면 일반적인 예외를 잡는 방법은 무엇입니까? 몇 가지 방법이 있습니다. 예외 객체를 원한다면 다음과 같이하십시오.

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message

놓칠 수없는 방식으로 사용자의주의를 끌 도록 하십시오 message ! 위와 같이 메시지가 다른 많은 메시지에 묻혀 있으면 인쇄하기에 충분하지 않을 수 있습니다. 사용자의 관심을 끌지 못하는 것은 모든 예외를 삼키는 데 큰 영향을 미치며,이 페이지의 답변을 읽은 후 사라져야 할 인상이 있다면 이것이 좋지 않은 것 입니다. 를 사용하여 except 블록 끝내기raisestatement로 발견 된 예외를 투명하게 다시 발생시켜 문제를 해결할 수 있습니다.

위와 except:인수없이 그냥 사용하는 것의 차이점 은 두 가지입니다.

  • 베어 except:는 검사 할 예외 개체를 제공하지 않습니다.
  • 예외는 SystemExit, KeyboardInterrupt그리고 GeneratorExit일반적으로 당신이 원하는 무엇을 위의 코드에 의해 잡힌되지 않습니다. 예외 계층을 참조하십시오 .

예외를 잡지 않으면 동일한 스택 추적을 원한다면 다음과 같이 얻을 수 있습니다 (여전히 except 절 안에 있음).

import traceback
print traceback.format_exc()

logging모듈 을 사용하는 경우 다음과 같이 예외를 메시지와 함께 로그에 인쇄 할 수 있습니다.

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

더 깊이 파고 스택을 검사하려면 변수 등을 살펴보고 except 블록 내부의 모듈 post_mortem기능을 사용하십시오 pdb.

import pdb
pdb.post_mortem()

나는이 마지막 방법이 버그를 사냥 할 때 귀중한 것으로 나타났습니다.


1
traceback.print_exc ()는 더 복잡한 "".join-thing과 같은 작업을 수행합니다.
Gurgeh

1
@Gurgeh 네, 그러나 그가 파일을 인쇄하거나 파일에 저장하거나 로그로 기록하거나 다른 작업을 수행할지 여부를 모르겠습니다.
Lauritz V. Thaulow

나는 downvoted하지 않았지만, 나는 당신이 처음에 큰 뚱뚱한 마모를 입었어야했기 때문에 이것이 필요하지 않다고 말했기 때문 입니다. 아마도 일반적인 예외를 잡으라고 제안하기 때문일 수 있습니다.
Rik Poggi

10
@Rik 나는 당신 이이 모든 것을 아주 잘 필요로 할 것이라고 생각한다 . 예를 들어, GUI와 백엔드가있는 프로그램이 있고 프로그램이 스택 추적으로 종료되는 대신 백엔드의 모든 예외를 GUI 메시지로 표시하려는 경우. 이러한 경우 일반 예외를 포착하고 대화 상자에 대한 역 추적 텍스트를 작성하고 예외도 기록한 후 디버그 모드 인 경우 사후 모모를 입력해야합니다.
Lauritz V. Thaulow

18
@RikPoggi : 순진한 생각. 다른 사람의 코드에서 예외를 잡아야하는 상황이 많으며 어떤 예외가 발생할지 모릅니다.
stackoverflowuser2010 년

63

예외 개체가 속한 클래스의 이름을 가져옵니다.

e.__class__.__name__

print_exc () 함수를 사용하면 모든 오류 메시지에 대한 필수 정보 인 스택 추적을 인쇄합니다.

이처럼 :

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception, e:
    print 'type is:', e.__class__.__name__
    print_exc()
    # print "exception happened!"

다음과 같이 출력됩니다 :

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi

그리고 인쇄 및 분석 후 코드는 예외를 처리하지 않고 다음을 실행하기로 결정할 수 있습니다 raise.

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        raise
    print "handling exception"

산출:

special case of CustomException not interfering

그리고 인터프리터는 예외를 인쇄합니다.

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi

raise원래 예외 후에 계속해서 호출 스택을 계속 전파합니다. ( 가능한 함정에주의하십시오 ) 새로운 예외를 제기하면 새로운 (더 짧은) 스택 추적이 필요합니다.

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        #raise CustomException(e.message)
        raise e
    print "handling exception"

산출:

special case of CustomException not interfering
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    

역 추적 에 원래 예외의 원점 인 calculate()line 함수가 포함되지 않은 방법에 주목하십시오 .9e


당신이 문자열로 역 추적을 저장하려면, 당신은 사용할 수 있습니다 traceback.format_exc()뿐만 아니라
Stevoisiak

1
e.__class__.__name__type(e).__name__위의 답변에서 제안한 것과 동일 합니까?
information_interchange

1
@information_interchange 예. 질문과 답변 내용은 시간이 지남에 따라 완전히 바뀌 었습니다. SO 기계류에 의해 다른 참가자들에게 통보되지 않는 것은 부끄러운 일입니다. (
Alex

14

일반적으로 예외 try: ... except가 너무 광범위하므로 가능한 모든 예외를 포착해서는 안됩니다 . 어떤 이유로 든 일어날 것으로 예상되는 것들을 잡아라. 예를 들어 디버깅하는 동안 일부 문제에 대해 더 자세히 알고 싶다면 실제로해야합니다.

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.

17
여기서 "never"라는 단어의 사용이 그렇게 잘못된 적이 없었습니다. 나는 try: ... except Exception:네트워크 의존 라이브러리의 사용 또는 그녀에게 이상한 물건을 보낼 수있는 데이터 마사지와 같은 많은 것들을 사용합니다. 당연히 나는 적절한 로깅도 가지고 있습니다. 이는 입력 데이터에 단일 실수가있을 경우 프로그램이 계속 작동하도록하는 데 중요합니다.
th 니

3
이제까지 사용하여 이메일을 보낼 때 제기 될 수있는 모든 예외를 잡으려고 시도 smtplib?
linusg 2016 년

1
모든 예외를 잡아야하는 특별한 경우가있을 수 있지만, 일반적으로 예상치 못한 오류를 숨기지 않도록 예상 한 것을 잡아야합니다. 물론 좋은 로깅도 좋은 생각입니다.
hochl

1
모든 예외를 잡는 것이 완벽하게 합리적입니다. 타사 라이브러리를 호출하는 경우 해당 라이브러리에서 어떤 예외가 발생하는지 알 수 없습니다. 이 경우 유일한 예외는 파일에 기록하는 등의 모든 예외를 포착하는 것입니다.
stackoverflowuser2010 년

알았어. 네, 맞아요. 모두 잡을 수있는 유효한 유스 케이스가 있음을 분명히하기 위해 대답을 바꾸겠습니다.
hochl

10

somefunction코딩 된 레거시 기능이 매우 나쁜 경우 가 아니라면 원하는 것을 요구하지 않아도됩니다.

여러 except절을 사용 하여 다른 예외를 다른 방식으로 처리 하십시오 .

try:
    someFunction()
except ValueError:
    # do something
except ZeroDivision:
    # do something else

요점은 일반적인 예외를 잡아서는 안되며 필요한 예외 만 잡아야한다는 것입니다. 예기치 않은 오류나 버그를 숨기고 싶지 않다고 확신합니다.


8
타사 라이브러리를 사용하는 경우 라이브러리에서 어떤 예외가 발생하는지 알 수 없습니다. 어떻게 그들 모두를 개별적으로 잡을 수 있습니까?
stackoverflowuser2010 년

8

대부분의 대답은 except (…) as (…):구문을 가리키고 있지만 (정확히), 동시에 코끼리가 sys.exc_info()기능 하는 방에있는 코끼리에 대해 이야기하고 싶은 사람은 없습니다 . sys 모듈 (강조 광산) 의 문서 에서 :

이 함수는 현재 처리중인 예외에 대한 정보를 제공하는 세 가지 값의 튜플을 반환합니다.
(…)
스택의 어느 곳에서나 예외가 처리되지 않으면 3 개의 None 값을 포함하는 튜플이 반환됩니다. 그렇지 않으면 리턴 된 값은 (type, value, traceback)입니다. 의미는 다음과 같습니다. type은 처리중인 예외 유형 (BaseException의 서브 클래스)을 가져옵니다 . value는 예외 인스턴스 (예외 유형의 인스턴스)를 가져옵니다. traceback은 예외가 원래 발생한 지점에서 콜 스택을 캡슐화하는 traceback 객체를 가져옵니다 (참조 매뉴얼 참조).

어떤 유형의 예외가 발생했는지 어떻게 알 수 있습니까?sys.exc_info() 의 원래 질문에 대한 가장 직접적인 대답으로 간주 될 수 있다고 생각합니다 .


1
그것이 발생하는 예외의 문제를 해결하므로 맨손 대신에 무엇을 넣어야하는지에 대한 올바른 대답 except입니다. 완벽을 기하기 위해에서 exctype, value = sys.exc_info()[:2]사용할 수있는 예외 유형을 알려줍니다 except.
Ondrej Burkert

5

시도 : 예외를 제외하고 someFunction ()

#this is how you get the type
excType = exc.__class__.__name__

#here we are printing out information about the Exception
print 'exception type', excType
print 'exception msg', str(exc)

#It's easy to reraise an exception with more information added to it
msg = 'there was a problem with someFunction'
raise Exception(msg + 'because of %s: %s' % (excType, exc))

-1 exc.__class__.__name__은 Alex의 답변에서 이미 제안 된대로 – stackoverflow.com/a/9824060/95735
Piotr Dobrogost

3

이 답변은 디버깅에는 적합하지만 프로그래밍 방식으로 예외를 테스트하는 경우 isinstance(e, SomeException)하위 클래스 SomeException도 테스트하므로 편리 하므로 예외 계층에 적용되는 기능을 만들 수 있습니다.


1

예외 처리 방법은 다음과 같습니다. 아이디어는 쉬운 경우 문제 해결을 시도하고 나중에 가능한 경우 더 바람직한 솔루션을 추가하는 것입니다. 예외를 생성하는 코드에서 문제를 해결하지 마십시오. 또는 해당 코드는 원래 알고리즘을 추적하지 못하므로 해당 시점까지 작성해야합니다. 그러나 문제를 해결하는 데 필요한 데이터를 전달하고 문제를 생성하는 코드 외부에서 문제를 해결할 수없는 경우를 대비하여 람다를 반환하십시오.

path = 'app.p'

def load():
    if os.path.exists(path):
        try:
            with open(path, 'rb') as file:
                data = file.read()
                inst = pickle.load(data)
        except Exception as e:
            inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
    else:
        inst = App()
    inst.loadWidgets()

# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
    class_name = e.__class__.__name__
    print(class_name + ': ' + str(e))
    print('\t during: ' + during)
    return easy

현재로서는 앱의 목적에 접선으로 생각하고 싶지 않기 때문에 복잡한 솔루션을 추가하지 않았습니다. 그러나 앞으로 가능한 솔루션에 대해 더 많이 알면 (앱이 더 많이 설계되었으므로)로 색인이 지정된 솔루션 사전을 추가 할 수 있습니다 during.

표시된 예에서 한 가지 해결책은 'app.p'파일이 실수로 삭제 된 경우 등 다른 곳에 저장된 앱 데이터를 찾는 것입니다.

현재로서는 예외 처리기를 작성하는 것이 현명한 아이디어가 아니기 때문에 (앱 디자인이 발전하기 때문에 아직 최선의 해결 방법을 모릅니다) 우리는 단순히 실행중인 것처럼 행동하기 쉬운 쉬운 수정을 반환합니다. 처음으로 (이 경우) 앱.


0

Lauritz의 답변에 추가하기 위해 예외 처리를위한 데코레이터 / 래퍼를 만들고 래퍼는 어떤 유형의 예외가 발생했는지 기록합니다.

class general_function_handler(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, obj, type=None):
        return self.__class__(self.func.__get__(obj, type))
    def __call__(self, *args, **kwargs):
        try:
            retval = self.func(*args, **kwargs)
        except Exception, e :
            logging.warning('Exception in %s' % self.func)
            template = "An exception of type {0} occured. Arguments:\n{1!r}"
            message = template.format(type(e).__name__, e.args)
            logging.exception(message)
            sys.exit(1) # exit on all exceptions for now
        return retval

데코레이터를 사용하여 클래스 메소드 또는 독립형 함수에서 호출 할 수 있습니다.

짤방 백업 봇

전체 예를 보려면 내 블로그를 참조하십시오 : http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/


0

다음과 같이 Lauritz가 권장하는대로 시작할 수 있습니다.

except Exception as ex:

그런 다음 print ex좋아합니다.

try:
    #your try code here
except Exception as ex:
    print ex

답을 독창적으로 표현할 수 있습니까?
GHC

1
확인 : 당신은 다음과 같이 잡힌 예외를 인쇄 할 수 있습니다 : 시도 : # 예를 들어 예외를 제외하고 여기에 코드를 시도하십시오 : 예를 들어 지금 인쇄 오류가 인쇄됩니다
Gura

-2

실제 예외는 다음과 같은 방식으로 캡처 할 수 있습니다.

try:
    i = 1/0
except Exception as e:
    print e

Python Tutorial 에서 예외에 대해 자세히 배울 수 있습니다 .


-2

귀하의 질문은 "예외를 일으킨 someFunction ()에서 발생한 일을 정확히 어떻게 알 수 있습니까?"입니다.

프로덕션 코드에서 예기치 않은 예외를 처리하는 방법 (많은 대답이 가정 한 것처럼)을 다루는 것이 아니라 개발 중에 특정 예외를 일으키는 원인을 찾는 방법을 묻는 것 같습니다.

가장 쉬운 방법은 변수를 검사 할 수 있도록 캐치되지 않은 예외가 발생하는 위치를 중지하고 종료하지 않는 디버거를 사용하는 것입니다. 예를 들어, Eclipse 오픈 소스 IDE의 PyDev가이를 수행 할 수 있습니다. 이클립스에 그 수 있도록 Debug 퍼스펙티브를 열고 선택 Manage Python Exception Breakpoints에서 Run메뉴를 확인 Suspend on uncaught exceptions.


-4

예외를 포착하지 말고 파이썬 프린트가 어떤 예외가 발생했는지 알려주는 역 추적을 삼가십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.