2010-05-16 4 views
11

긴 제목으로 불편을 끼쳐 드려 죄송합니다. 그러나 제 질문에 대해 가장 잘 설명하는 것으로 보입니다.주어진 라이브러리 함수가 파이썬에서 발생하는 모든 예외 목록을 어떻게 찾을 수 있습니까?

기본적으로 공식적인 python 문서에서 예외 정보를 찾는 데 어려움을 겪고 있습니다. , 잘 작동 한 나는 TMP// 쓰기 액세스를 가지고, 충분한 디스크 공간이

from shutil import move 
move('somefile.txt', '/tmp/somefile.txt') 

예를 들어, 하나 개의 프로그램에서 내가 현재 쓰고 있어요, 나는 또 shutil libary의 이동 기능을 사용하고 있습니다 다른 모든 요구 사항이 충족되는 경우 일반적인 코드를 작성할 때

는 그러나, 이러한 요인을 보장하는 것이 어렵다, 그래서 하나는 일반적으로 예외를 사용

from shutil import move 
try: 
    move('somefile.txt', '/tmp/somefile.txt') 
except: 
    print 'Move failed for some reason.' 

실제로 대신 모든 것을 잡는 던져 적절한 예외를 포착하고 싶습니다를하지만 대부분의 파이썬 모듈에서 던져진 예외 목록을 찾을 수 없습니다. 주어진 함수가 어떤 예외를 던질 수 있는지, 그리고 왜 예외인지를 알 수있는 방법이 있습니까? 이 방법은 내가 각 예외에 대한 적절한 사례를 만들 수 있습니다, 예를 들면 :

from shutil import move 
try: 
    move('somefile.txt', '/tmp/somefile.txt') 
except PermissionDenied: 
    print 'No permission.' 
except DestinationDoesNotExist: 
    print "/tmp/ doesn't exist" 
except NoDiskSpace: 
    print 'No diskspace available.' 

대답 포인트는 어떻게 든 공식 문서에서 간과 한 몇 가지 관련 문서 나 링크, 또는 확실한을 제공 할 수 있습니다 누구든지로 이동 방법으로 예외가 어떤 함수에 의해 던져 졌는지 정확하게 파악할 수 있습니다. 이유는 무엇입니까?

감사합니다.

업데이트 : : 특정 기능에 의해 어떤 오류가 발생하는지 파악하는 방법은 100 % 간단하지 않습니다. 메타 프로그래밍을 사용하면 단순한 사례를 찾아 낼 수 있고 몇 가지 예외를 나열 할 수있는 것처럼 보입니다. 그러나 이것은 특히 유용하거나 편리한 방법은 아닙니다.

저는 궁극적으로 각 파이썬 함수에 의해 발생되는 예외를 정의하는 표준이있을 것이며이 정보는 공식 문서에 포함될 것이라고 생각하고 싶습니다. 그때까지는 가장 예외적 인 일처럼 보이기 때문에 예외를 통과시키고 사용자에게 오류를 허용 할 것입니다.

+0

, I 돈 : 여기

는 AST 걸을 수있는 코드입니다, 그냥 네 책의 갱에서 "방문자 패턴"을 구현하는 워커를 만들 compiler.visitor 인터페이스를 사용 확실하게 말할 수있는 경험이 있지만, Java의'throws '와 동등한 점은 유형에 대한 함수 매개 변수 테스트 (함수가 오리 유형 반복 가능을 처리 할 수있는 경우)가 적합하지 않음을 느낍니다. – msw

답변

11

메시를 증폭하려면 회복 방법을 알고있는 실패 모드가 무엇인지 예상하십시오. 이안 비킹 (Eric Bicking)은 Eli Bendersky의 note처럼 몇 가지 중요한 원칙을 다루는 an article을 작성했습니다.

예제 코드의 문제점은 이 아니고이 아닌 오류를 처리하고이를 무시한 것입니다. 귀하의 코드는 NameError로 무엇을해야 하는지를 "알지 못합니다"그리고 그것을 전달하는 것 외에는해야 할 일이 많지 않습니다. 당신이 세부 사항을 추가해야한다고 생각한다면 Bicking의 Re-raise를보십시오.

IOError 및 OSError는 shutil.move의 경우 "예상 가능"하지만 반드시 처리 할 필요는 없습니다. 그리고 함수 호출자는 파일을 이동하기를 원했고 엘리가 쓴 "계약"이 깨지면 그 자체가 깨질 수 있습니다.

예상치 못한 것을 고칠 수는 있지만 수정할 수는 없지만 발신자가 예상하지 못한 것을 처리하도록 할 수 있습니다. "거래하는"코드가 7 단계 위로 올라가더라도 main에 쌓아 두십시오.

+1

OP 문제를 좀 더 해결하기 위해, 여기에 'IOError'와'OSError'가 설명되어 있습니다 : http://docs.python.org/library/exceptions.html. 하지만 보시다시피 두 가지 모두 호스트 시스템과 OS에 크게 의존합니다. 정말로 모든 종류의 관련 오류를 삼키고 싶다면'EnvironmentError as e : print e.strerror'와 같은 것을해야합니다. 그렇지 않으면'errorno'를 확인하고, 특정 사례를 처리하고, 나머지를'raise'하는 것을 잊지 마세요. –

+0

@ THC4k :'errorno'가 아니라'errno'입니다. – tzot

+0

동의합니다! 코드에서 처리 할 수있는 것과 수행 할 수없는 것을 아는 것이 중요합니다. – yaobin

2

이러한 작업은 일반적으로 libc 함수 및 운영 체제 호출을 사용하므로 대부분 IOError 또는 OSError에 errno 숫자가 표시됩니다. 이러한 오류는 해당 libc/OS 호출의 맨 페이지에 나열되어 있습니다.

나는

+1

당신은 "모든 예외 목록을 나열하는 것이 좋을 것"이라고 썼다. 나는 그 생각에 의문을 갖기 시작했다. 언어가'throws' 절을 강요하지 않으면, 문서 솔루션은 "explicit is implicit than maxim"격언에 실패합니다. 명시 적 계약의 결여와 역동적 인 바인딩 (현재 '수입'을 포함하여) 사이에서 당신은 정말로 무엇이 상승할지 모릅니다. 예상치 못한 것을 처리 할 수는 없으며 EnvironmentErrors가 예상 가능하고 처리 가능하다는 것을 알기 때문에 Assertion 오류를 잡기를 원하지 않으며 MemoryError 수정으로 코드가 산재 해있는 것을 원하지 않습니다. – msw

4

파이썬은 예외가 달리 발생하는 선언을 위해 지금 메커니즘이 없습니다 ...이,이 문서에 나와있는 모든 예외가 좋은 것입니다 아마도 완전한 답변 아니라는 것을 알고 (예를 들면 자바). (Java에서는 무엇에 의해 예외가 발생하는지 정확히 정의해야하며 유틸리티 메소드 중 하나가 다른 예외를 throw해야하는 경우이를 호출하는 모든 메소드에이를 추가해야합니다.

그래서 파이썬의 어떤 비트에 의해 던져지는 예외를 정확하게 발견하기 원한다면 문서와 소스를 검사해야합니다.

그러나 파이썬은 정말 좋은 예외 계층 구조를 가지고 있습니다.

아래의 예외 계층 구조를 연구하면 잡기를 원하는 오류 수퍼 클래스를 StandardError라고합니다. 정상 작동에서 생성 될 수있는 모든 오류를 잡아야합니다. 문자열로에 오류를 돌리면 무엇이 잘못되었는지에 관해서는 사용자에게 합리적인 아이디어를 줄 것이다, 그래서 위의 코드를

from shutil import move 
try: 
    move('somefile.txt', '/tmp/somefile.txt') 
except StandardError, e: 
    print 'Move failed: %s' % e 

예외 계층 구조도

BaseException 
|---Exception 
|---|---StandardError 
|---|---|---ArithmeticError 
|---|---|---|---FloatingPointError 
|---|---|---|---OverflowError 
|---|---|---|---ZeroDivisionError 
|---|---|---AssertionError 
|---|---|---AttributeError 
|---|---|---BufferError 
|---|---|---EOFError 
|---|---|---EnvironmentError 
|---|---|---|---IOError 
|---|---|---|---OSError 
|---|---|---ImportError 
|---|---|---LookupError 
|---|---|---|---IndexError 
|---|---|---|---KeyError 
|---|---|---MemoryError 
|---|---|---NameError 
|---|---|---|---UnboundLocalError 
|---|---|---ReferenceError 
|---|---|---RuntimeError 
|---|---|---|---NotImplementedError 
|---|---|---SyntaxError 
|---|---|---|---IndentationError 
|---|---|---|---|---TabError 
|---|---|---SystemError 
|---|---|---TypeError 
|---|---|---ValueError 
|---|---|---|---UnicodeError 
|---|---|---|---|---UnicodeDecodeError 
|---|---|---|---|---UnicodeEncodeError 
|---|---|---|---|---UnicodeTranslateError 
|---|---StopIteration 
|---|---Warning 
|---|---|---BytesWarning 
|---|---|---DeprecationWarning 
|---|---|---FutureWarning 
|---|---|---ImportWarning 
|---|---|---PendingDeprecationWarning 
|---|---|---RuntimeWarning 
|---|---|---SyntaxWarning 
|---|---|---UnicodeWarning 
|---|---|---UserWarning 
|---GeneratorExit 
|---KeyboardInterrupt 
|---SystemExit 

이 같아야 좋을 것 자신의 예외를 정의 할 때 Exception이 아닌 StandardError를 기반으로해야한다는 것을 의미합니다.

Base class for all standard Python exceptions that do not represent 
interpreter exiting. 
+0

이것은 "예상 된"런타임 오류 대신 진정으로 버그를 나타내는 SyntaxError, AssertionError, NameError 등을 삼켜 버리는 나쁜 생각입니다. – msw

+0

'except :'보다 여전히 좋습니다. – fossilet

3

네, (간단한 경우) 할 수 있지만 약간의 메타 프로그래밍이 필요합니다. 다른 답변과 마찬가지로 함수는 특정 오류 유형을 throw한다고 선언하지 않으므로 모듈을보고 어떤 예외 유형이 정의되는지 또는 어떤 예외 유형이 발생하는지 확인해야합니다. 이렇게하려면 문서를 괴롭 히거나 Python API를 활용하십시오.

모듈이 정의하는 예외 유형을 찾으려면 모듈 사전 module.__dict__의 각 객체를 통과하는 간단한 스크립트를 작성하고 "오류"단어로 끝나는 지 또는 예외 클래스의 서브 클래스인지 확인하십시오.

내가 shutils 당신의 예에서이 작업을 실행하면
def listexns(mod): 
    """Saved as: http://gist.github.com/402861 
    """ 
    module = __import__(mod) 
    exns = [] 
    for name in module.__dict__: 
     if (issubclass(module.__dict__[name], Exception) or 
      name.endswith('Error')): 
      exns.append(name) 
    for name in exns: 
     print '%s.%s is an exception type' % (str(mod), name) 
    return 

나는이 얻을 :

오류 유형이 정의를 알 수 있지만, 사람이 던져하지하는
$ python listexn.py shutil 
Looking for exception types in module: shutil 
shutil.Error is an exception type 
shutil.WindowsError is an exception type 
$ 

. 후자를 얻으려면 Python 해석기가 모듈을 구문 분석 할 때 생성 된 추상 구문 트리를 살펴보고 모든 raise 문을 찾은 다음 발생한 이름 목록을 저장해야합니다. 이 코드는 조금 긴, 그래서 첫 번째 I 출력 해 두자

$ python listexn-raised.py /usr/lib/python2.6/shutil.py 
Looking for exception types in: /usr/lib/python2.6/shutil.py 
/usr/lib/python2.6/shutil.py:OSError is an exception type 
/usr/lib/python2.6/shutil.py:Error is an exception type 
$ 

그래서, 지금 우리가 shutil.py 오류 유형 ErrorWindowsError을 정의하고 예외 유형 OSErrorError을 제기 것을 알고 있습니다.조금 더 완성되기를 원한다면 except 절을 검사하여 shutil 예외를 확인하는 또 다른 방법을 작성할 수 있습니다. 파이썬 초심자로

class ExceptionFinder(visitor.ASTVisitor): 
    """List all exceptions raised by a module. 
    Saved as: http://gist.github.com/402869 
    """ 

    def __init__(self, filename): 
     visitor.ASTVisitor.__init__(self) 
     self.filename = filename 
     self.exns = set() 
     return 

    def __visitName(self, node): 
     """Should not be called by generic visit, otherwise every name 
     will be reported as an exception type. 
     """ 
     self.exns.add(node.name) 
     return 

    def __visitCallFunc(self, node): 
     """Should not be called by generic visit, otherwise every name 
     will be reported as an exception type. 
     """ 
     self.__visitName(node.node) 
     return 

    def visitRaise(self, node): 
     """Visit a raise statement. 
     Cheat the default dispatcher. 
     """ 
     if issubclass(node.expr1, compiler.ast.Name): 
      self.__visitName(node.expr1) 
     elif isinstance(node.expr1, compiler.ast.CallFunc): 
      self.__visitCallFunc(node.expr1) 
     return 
+3

아니요, 이론이나 실습 모두에서 모든 예외를 나열 할 수는 없습니다. 실제로는 무엇이든 Python의 C 부분에서 AssertionError에서 ZeroDivisionError로 많은 예외를 발생시킬 수 있습니다. 이론적으로,이 유형이 무엇인지 알아낼 수는 없습니다 :'유형 올리기 (raw_input ("Raise What?"), (Exception,), {})'(모든 입력에 대해 * 새로운 유형의 예외 *가 발생 함) –

+1

좋습니다. 사실입니다. 여기서 파이썬 예외 만 나열하고 정적 분석은 특정 예제를 포착하지 않습니다. 귀하의 예는 질문이 계산 불가능하다는 것을 보여 주지만, 실제로는 OP에서 요구했던 제 3 자 코드를 사용하는 데 필요한 대답은 합리적입니다. – snim2

+0

정말이 대답에 감사드립니다. 나는 그것을 대단히 유용하고 통찰력있는 것으로 발견했다. 그러나 응답을 읽은 후에 내가 찾고있는 것을 찾는 확실한 방법이없는 것 같아서 대답 크레디트를주지 않았습니다. 솔루션은 단순한 경우에는 효과가있는 것처럼 보일 수 있지만 일반적인 용도로는 편리하지 않거나 우아하지 않습니다 (각 기능에 대해 솔루션을 실행하는 데 어려움이 있습니다). 그러나 어쨌든이 점에 대해 감사드립니다. 그건 진짜 흥미 로웠 어. – rdegges

관련 문제